Skip to content

Instantly share code, notes, and snippets.

@granthenke
Last active February 25, 2016 08:01
Show Gist options
  • Save granthenke/dae9e60b5e548acead58 to your computer and use it in GitHub Desktop.
Save granthenke/dae9e60b5e548acead58 to your computer and use it in GitHub Desktop.
<h4>Api Keys</h4><p>The following are the numeric codes that the ApiKey in the request can take for each of the above request types.</p><table class="data-table"><tbody>
<tr>
<th>Name</th>
<th>Key</th>
</tr>
<tr>
<td>Produce</td><td>0</td></tr>
<tr>
<td>Fetch</td><td>1</td></tr>
<tr>
<td>Offsets</td><td>2</td></tr>
<tr>
<td>Metadata</td><td>3</td></tr>
<tr>
<td>LeaderAndIsr</td><td>4</td></tr>
<tr>
<td>StopReplica</td><td>5</td></tr>
<tr>
<td>UpdateMetadata</td><td>6</td></tr>
<tr>
<td>ControlledShutdown</td><td>7</td></tr>
<tr>
<td>OffsetCommit</td><td>8</td></tr>
<tr>
<td>OffsetFetch</td><td>9</td></tr>
<tr>
<td>GroupCoordinator</td><td>10</td></tr>
<tr>
<td>JoinGroup</td><td>11</td></tr>
<tr>
<td>Heartbeat</td><td>12</td></tr>
<tr>
<td>LeaveGroup</td><td>13</td></tr>
<tr>
<td>SyncGroup</td><td>14</td></tr>
<tr>
<td>DescribeGroups</td><td>15</td></tr>
<tr>
<td>ListGroups</td><td>16</td></tr>
</table>
<h4>Error Codes</h4><p>We use numeric codes to indicate what problem occurred on the server. These can be translated by the client into exceptions or whatever the appropriate error handling mechanism in the client language. Here is a table of the error codes currently in use:</p><table class="data-table"><tbody>
<tr>
<th>Error</th>
<th>Code</th>
<th>Retriable</th>
<th>Description</th>
</tr>
<tr>
<td>UNKNOWN</td><td>-1</td><td>False</td><td>The server experienced an unexpected error when processing the request</td></tr>
<tr>
<td>NONE</td><td>0</td><td>False</td><td></td></tr>
<tr>
<td>OFFSET_OUT_OF_RANGE</td><td>1</td><td>False</td><td>The requested offset is not within the range of offsets maintained by the server.</td></tr>
<tr>
<td>CORRUPT_MESSAGE</td><td>2</td><td>True</td><td>This message has failed its CRC checksum, exceeds the valid size, or is otherwise corrupt.</td></tr>
<tr>
<td>UNKNOWN_TOPIC_OR_PARTITION</td><td>3</td><td>True</td><td>This server does not host this topic-partition.</td></tr>
<tr>
<td>INVALID_FETCH_SIZE</td><td>4</td><td>False</td><td>The requested fetch size is invalid.</td></tr>
<tr>
<td>LEADER_NOT_AVAILABLE</td><td>5</td><td>True</td><td>There is no leader for this topic-partition as we are in the middle of a leadership election.</td></tr>
<tr>
<td>NOT_LEADER_FOR_PARTITION</td><td>6</td><td>True</td><td>This server is not the leader for that topic-partition.</td></tr>
<tr>
<td>REQUEST_TIMED_OUT</td><td>7</td><td>True</td><td>The request timed out.</td></tr>
<tr>
<td>BROKER_NOT_AVAILABLE</td><td>8</td><td>False</td><td>The broker is not available.</td></tr>
<tr>
<td>REPLICA_NOT_AVAILABLE</td><td>9</td><td>False</td><td>The replica is not available for the requested topic-partition</td></tr>
<tr>
<td>MESSAGE_TOO_LARGE</td><td>10</td><td>False</td><td>The request included a message larger than the max message size the server will accept.</td></tr>
<tr>
<td>STALE_CONTROLLER_EPOCH</td><td>11</td><td>False</td><td>The controller moved to another broker.</td></tr>
<tr>
<td>OFFSET_METADATA_TOO_LARGE</td><td>12</td><td>False</td><td>The metadata field of the offset request was too large.</td></tr>
<tr>
<td>NETWORK_EXCEPTION</td><td>13</td><td>True</td><td>The server disconnected before a response was received.</td></tr>
<tr>
<td>GROUP_LOAD_IN_PROGRESS</td><td>14</td><td>True</td><td>The coordinator is loading and hence can't process requests for this group.</td></tr>
<tr>
<td>GROUP_COORDINATOR_NOT_AVAILABLE</td><td>15</td><td>True</td><td>The group coordinator is not available.</td></tr>
<tr>
<td>NOT_COORDINATOR_FOR_GROUP</td><td>16</td><td>True</td><td>This is not the correct coordinator for this group.</td></tr>
<tr>
<td>INVALID_TOPIC_EXCEPTION</td><td>17</td><td>False</td><td>The request attempted to perform an operation on an invalid topic.</td></tr>
<tr>
<td>RECORD_LIST_TOO_LARGE</td><td>18</td><td>False</td><td>The request included message batch larger than the configured segment size on the server.</td></tr>
<tr>
<td>NOT_ENOUGH_REPLICAS</td><td>19</td><td>True</td><td>Messages are rejected since there are fewer in-sync replicas than required.</td></tr>
<tr>
<td>NOT_ENOUGH_REPLICAS_AFTER_APPEND</td><td>20</td><td>True</td><td>Messages are written to the log, but to fewer in-sync replicas than required.</td></tr>
<tr>
<td>INVALID_REQUIRED_ACKS</td><td>21</td><td>False</td><td>Produce request specified an invalid value for required acks.</td></tr>
<tr>
<td>ILLEGAL_GENERATION</td><td>22</td><td>False</td><td>Specified group generation id is not valid.</td></tr>
<tr>
<td>INCONSISTENT_GROUP_PROTOCOL</td><td>23</td><td>False</td><td>The group member's supported protocols are incompatible with those of existing members.</td></tr>
<tr>
<td>INVALID_GROUP_ID</td><td>24</td><td>False</td><td>The configured groupId is invalid</td></tr>
<tr>
<td>UNKNOWN_MEMBER_ID</td><td>25</td><td>False</td><td>The coordinator is not aware of this member.</td></tr>
<tr>
<td>INVALID_SESSION_TIMEOUT</td><td>26</td><td>False</td><td>The session timeout is not within an acceptable range.</td></tr>
<tr>
<td>REBALANCE_IN_PROGRESS</td><td>27</td><td>False</td><td>The group is rebalancing, so a rejoin is needed.</td></tr>
<tr>
<td>INVALID_COMMIT_OFFSET_SIZE</td><td>28</td><td>False</td><td>The committing offset data size is not valid</td></tr>
<tr>
<td>TOPIC_AUTHORIZATION_FAILED</td><td>29</td><td>False</td><td>Not authorized to access topics: [Topic authorization failed.]</td></tr>
<tr>
<td>GROUP_AUTHORIZATION_FAILED</td><td>30</td><td>False</td><td>Not authorized to access group: Group authorization failed.</td></tr>
<tr>
<td>CLUSTER_AUTHORIZATION_FAILED</td><td>31</td><td>False</td><td>Cluster authorization failed.</td></tr>
<tr>
<td>INVALID_TIMESTAMP</td><td>32</td><td>False</td><td>The timestamp of the message is out of acceptable range.</td></tr>
</table>
<h4>Headers:</h4><pre>Request Header => api_key api_version correlation_id client_id
api_key => INT16
api_version => INT16
correlation_id => INT32
client_id => NULLABLE_STRING
</pre>
<pre>Response Header => correlation_id
correlation_id => INT32
</pre>
<h4>Produce API (Key: 0):</h4>
<b>Requests:</b><br>
<p><pre>Produce Request (Version: 0) => acks timeout [topic_data]
topic_data => topic [data]
data => partition record_set
partition => INT32
record_set => BYTES
topic => STRING
acks => INT16
timeout => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>acks</td><td>The number of nodes that should replicate the produce before returning. -1 indicates the full ISR.</td></tr>
<tr>
<td>timeout</td><td>The time to await a response in ms.</td></tr>
<tr>
<td>topic_data</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>data</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<p><pre>Produce Request (Version: 1) => acks timeout [topic_data]
topic_data => topic [data]
data => partition record_set
partition => INT32
record_set => BYTES
topic => STRING
acks => INT16
timeout => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>acks</td><td>The number of nodes that should replicate the produce before returning. -1 indicates the full ISR.</td></tr>
<tr>
<td>timeout</td><td>The time to await a response in ms.</td></tr>
<tr>
<td>topic_data</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>data</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<p><pre>Produce Request (Version: 2) => acks timeout [topic_data]
topic_data => topic [data]
data => partition record_set
partition => INT32
record_set => BYTES
topic => STRING
acks => INT16
timeout => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>acks</td><td>The number of nodes that should replicate the produce before returning. -1 indicates the full ISR.</td></tr>
<tr>
<td>timeout</td><td>The time to await a response in ms.</td></tr>
<tr>
<td>topic_data</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>data</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>Produce Response (Version: 0) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code base_offset
partition => INT32
error_code => INT16
base_offset => INT64
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>base_offset</td><td></td></tr>
</table>
</p>
<p><pre>Produce Response (Version: 1) => [responses] throttle_time_ms
responses => topic [partition_responses]
partition_responses => partition error_code base_offset
partition => INT32
error_code => INT16
base_offset => INT64
topic => STRING
throttle_time_ms => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>base_offset</td><td></td></tr>
<tr>
<td>throttle_time_ms</td><td>Duration in milliseconds for which the request was throttled due to quota violation. (Zero if the request did not violate any quota.)</td></tr>
</table>
</p>
<p><pre>Produce Response (Version: 2) => [responses] throttle_time_ms
responses => topic [partition_responses]
partition_responses => partition error_code base_offset timestamp
partition => INT32
error_code => INT16
base_offset => INT64
timestamp => INT64
topic => STRING
throttle_time_ms => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td></td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>base_offset</td><td></td></tr>
<tr>
<td>timestamp</td><td>The timestamp returned by broker after appending the messages. If CreateTime is used for the topic, the timestamp will be -1. If LogAppendTime is used for the topic, the timestamp will be the broker local time when the messages are appended.</td></tr>
<tr>
<td>throttle_time_ms</td><td>Duration in milliseconds for which the request was throttled due to quota violation. (Zero if the request did not violate any quota.)</td></tr>
</table>
</p>
<h4>Fetch API (Key: 1):</h4>
<b>Requests:</b><br>
<p><pre>Fetch Request (Version: 0) => replica_id max_wait_time min_bytes [topics]
topics => topic [partitions]
partitions => partition fetch_offset max_bytes
partition => INT32
fetch_offset => INT64
max_bytes => INT32
topic => STRING
replica_id => INT32
max_wait_time => INT32
min_bytes => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>replica_id</td><td>Broker id of the follower. For normal consumers, use -1.</td></tr>
<tr>
<td>max_wait_time</td><td>Maximum time in ms to wait for the response.</td></tr>
<tr>
<td>min_bytes</td><td>Minimum bytes to accumulate in the response.</td></tr>
<tr>
<td>topics</td><td>Topics to fetch.</td></tr>
<tr>
<td>topic</td><td>Topic to fetch.</td></tr>
<tr>
<td>partitions</td><td>Partitions to fetch.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>fetch_offset</td><td>Message offset.</td></tr>
<tr>
<td>max_bytes</td><td>Maximum bytes to fetch.</td></tr>
</table>
</p>
<p><pre>Fetch Request (Version: 1) => replica_id max_wait_time min_bytes [topics]
topics => topic [partitions]
partitions => partition fetch_offset max_bytes
partition => INT32
fetch_offset => INT64
max_bytes => INT32
topic => STRING
replica_id => INT32
max_wait_time => INT32
min_bytes => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>replica_id</td><td>Broker id of the follower. For normal consumers, use -1.</td></tr>
<tr>
<td>max_wait_time</td><td>Maximum time in ms to wait for the response.</td></tr>
<tr>
<td>min_bytes</td><td>Minimum bytes to accumulate in the response.</td></tr>
<tr>
<td>topics</td><td>Topics to fetch.</td></tr>
<tr>
<td>topic</td><td>Topic to fetch.</td></tr>
<tr>
<td>partitions</td><td>Partitions to fetch.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>fetch_offset</td><td>Message offset.</td></tr>
<tr>
<td>max_bytes</td><td>Maximum bytes to fetch.</td></tr>
</table>
</p>
<p><pre>Fetch Request (Version: 2) => replica_id max_wait_time min_bytes [topics]
topics => topic [partitions]
partitions => partition fetch_offset max_bytes
partition => INT32
fetch_offset => INT64
max_bytes => INT32
topic => STRING
replica_id => INT32
max_wait_time => INT32
min_bytes => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>replica_id</td><td>Broker id of the follower. For normal consumers, use -1.</td></tr>
<tr>
<td>max_wait_time</td><td>Maximum time in ms to wait for the response.</td></tr>
<tr>
<td>min_bytes</td><td>Minimum bytes to accumulate in the response.</td></tr>
<tr>
<td>topics</td><td>Topics to fetch.</td></tr>
<tr>
<td>topic</td><td>Topic to fetch.</td></tr>
<tr>
<td>partitions</td><td>Partitions to fetch.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>fetch_offset</td><td>Message offset.</td></tr>
<tr>
<td>max_bytes</td><td>Maximum bytes to fetch.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>Fetch Response (Version: 0) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code high_watermark record_set
partition => INT32
error_code => INT16
high_watermark => INT64
record_set => BYTES
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>high_watermark</td><td>Last committed offset.</td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<p><pre>Fetch Response (Version: 1) => throttle_time_ms [responses]
responses => topic [partition_responses]
partition_responses => partition error_code high_watermark record_set
partition => INT32
error_code => INT16
high_watermark => INT64
record_set => BYTES
topic => STRING
throttle_time_ms => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>throttle_time_ms</td><td>Duration in milliseconds for which the request was throttled due to quota violation. (Zero if the request did not violate any quota.)</td></tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>high_watermark</td><td>Last committed offset.</td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<p><pre>Fetch Response (Version: 2) => throttle_time_ms [responses]
responses => topic [partition_responses]
partition_responses => partition error_code high_watermark record_set
partition => INT32
error_code => INT16
high_watermark => INT64
record_set => BYTES
topic => STRING
throttle_time_ms => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>throttle_time_ms</td><td>Duration in milliseconds for which the request was throttled due to quota violation. (Zero if the request did not violate any quota.)</td></tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>high_watermark</td><td>Last committed offset.</td></tr>
<tr>
<td>record_set</td><td></td></tr>
</table>
</p>
<h4>Offsets API (Key: 2):</h4>
<b>Requests:</b><br>
<p><pre>Offsets Request (Version: 0) => replica_id [topics]
topics => topic [partitions]
partitions => partition timestamp max_num_offsets
partition => INT32
timestamp => INT64
max_num_offsets => INT32
topic => STRING
replica_id => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>replica_id</td><td>Broker id of the follower. For normal consumers, use -1.</td></tr>
<tr>
<td>topics</td><td>Topics to list offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to list offset.</td></tr>
<tr>
<td>partitions</td><td>Partitions to list offset.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>timestamp</td><td>Timestamp.</td></tr>
<tr>
<td>max_num_offsets</td><td>Maximum offsets to return.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>Offsets Response (Version: 0) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code [offsets]
partition => INT32
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>offsets</td><td>A list of offsets.</td></tr>
</table>
</p>
<h4>Metadata API (Key: 3):</h4>
<b>Requests:</b><br>
<p><pre>Metadata Request (Version: 0) => [topics]
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>topics</td><td>An array of topics to fetch metadata for. If no topics are specified fetch metadata for all topics.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>Metadata Response (Version: 0) => [brokers] [topic_metadata]
brokers => node_id host port
node_id => INT32
host => STRING
port => INT32
topic_metadata => topic_error_code topic [partition_metadata]
partition_metadata => partition_error_code partition_id leader [replicas] [isr]
partition_error_code => INT16
partition_id => INT32
leader => INT32
topic_error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>brokers</td><td>Host and port information for all brokers.</td></tr>
<tr>
<td>node_id</td><td>The broker id.</td></tr>
<tr>
<td>host</td><td>The hostname of the broker.</td></tr>
<tr>
<td>port</td><td>The port on which the broker accepts requests.</td></tr>
<tr>
<td>topic_metadata</td><td></td></tr>
<tr>
<td>topic_error_code</td><td>The error code for the given topic.</td></tr>
<tr>
<td>topic</td><td>The name of the topic</td></tr>
<tr>
<td>partition_metadata</td><td>Metadata for each partition of the topic.</td></tr>
<tr>
<td>partition_error_code</td><td>The error code for the partition, if any.</td></tr>
<tr>
<td>partition_id</td><td>The id of the partition.</td></tr>
<tr>
<td>leader</td><td>The id of the broker acting as leader for this partition.</td></tr>
<tr>
<td>replicas</td><td>The set of all nodes that host this partition.</td></tr>
<tr>
<td>isr</td><td>The set of nodes that are in sync with the leader for this partition.</td></tr>
</table>
</p>
<h4>LeaderAndIsr API (Key: 4):</h4>
<b>Requests:</b><br>
<p><pre>LeaderAndIsr Request (Version: 0) => controller_id controller_epoch [partition_states] [live_leaders]
partition_states => topic partition controller_epoch leader leader_epoch [isr] zk_version [replicas]
topic => STRING
partition => INT32
controller_epoch => INT32
leader => INT32
leader_epoch => INT32
zk_version => INT32
live_leaders => id host port
id => INT32
host => STRING
port => INT32
controller_id => INT32
controller_epoch => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>controller_id</td><td>The controller id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>partition_states</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>leader</td><td>The broker id for the leader.</td></tr>
<tr>
<td>leader_epoch</td><td>The leader epoch.</td></tr>
<tr>
<td>isr</td><td>The in sync replica ids.</td></tr>
<tr>
<td>zk_version</td><td>The ZK version.</td></tr>
<tr>
<td>replicas</td><td>The replica ids.</td></tr>
<tr>
<td>live_leaders</td><td></td></tr>
<tr>
<td>id</td><td>The broker id.</td></tr>
<tr>
<td>host</td><td>The hostname of the broker.</td></tr>
<tr>
<td>port</td><td>The port on which the broker accepts requests.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>LeaderAndIsr Response (Version: 0) => error_code [partitions]
partitions => topic partition error_code
topic => STRING
partition => INT32
error_code => INT16
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
<tr>
<td>partitions</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
</table>
</p>
<h4>StopReplica API (Key: 5):</h4>
<b>Requests:</b><br>
<p><pre>StopReplica Request (Version: 0) => controller_id controller_epoch delete_partitions [partitions]
partitions => topic partition
topic => STRING
partition => INT32
controller_id => INT32
controller_epoch => INT32
delete_partitions => INT8
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>controller_id</td><td>The controller id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>delete_partitions</td><td>Boolean which indicates if replica's partitions must be deleted.</td></tr>
<tr>
<td>partitions</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>StopReplica Response (Version: 0) => error_code [partitions]
partitions => topic partition error_code
topic => STRING
partition => INT32
error_code => INT16
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
<tr>
<td>partitions</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
</table>
</p>
<h4>UpdateMetadata API (Key: 6):</h4>
<b>Requests:</b><br>
<p><pre>UpdateMetadata Request (Version: 0) => controller_id controller_epoch [partition_states] [live_brokers]
partition_states => topic partition controller_epoch leader leader_epoch [isr] zk_version [replicas]
topic => STRING
partition => INT32
controller_epoch => INT32
leader => INT32
leader_epoch => INT32
zk_version => INT32
live_brokers => id host port
id => INT32
host => STRING
port => INT32
controller_id => INT32
controller_epoch => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>controller_id</td><td>The controller id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>partition_states</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>leader</td><td>The broker id for the leader.</td></tr>
<tr>
<td>leader_epoch</td><td>The leader epoch.</td></tr>
<tr>
<td>isr</td><td>The in sync replica ids.</td></tr>
<tr>
<td>zk_version</td><td>The ZK version.</td></tr>
<tr>
<td>replicas</td><td>The replica ids.</td></tr>
<tr>
<td>live_brokers</td><td></td></tr>
<tr>
<td>id</td><td>The broker id.</td></tr>
<tr>
<td>host</td><td>The hostname of the broker.</td></tr>
<tr>
<td>port</td><td>The port on which the broker accepts requests.</td></tr>
</table>
</p>
<p><pre>UpdateMetadata Request (Version: 1) => controller_id controller_epoch [partition_states] [live_brokers]
partition_states => topic partition controller_epoch leader leader_epoch [isr] zk_version [replicas]
topic => STRING
partition => INT32
controller_epoch => INT32
leader => INT32
leader_epoch => INT32
zk_version => INT32
live_brokers => id [end_points]
end_points => port host security_protocol_type
port => INT32
host => STRING
security_protocol_type => INT16
id => INT32
controller_id => INT32
controller_epoch => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>controller_id</td><td>The controller id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>partition_states</td><td></td></tr>
<tr>
<td>topic</td><td>Topic name.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>controller_epoch</td><td>The controller epoch.</td></tr>
<tr>
<td>leader</td><td>The broker id for the leader.</td></tr>
<tr>
<td>leader_epoch</td><td>The leader epoch.</td></tr>
<tr>
<td>isr</td><td>The in sync replica ids.</td></tr>
<tr>
<td>zk_version</td><td>The ZK version.</td></tr>
<tr>
<td>replicas</td><td>The replica ids.</td></tr>
<tr>
<td>live_brokers</td><td></td></tr>
<tr>
<td>id</td><td>The broker id.</td></tr>
<tr>
<td>end_points</td><td></td></tr>
<tr>
<td>port</td><td>The port on which the broker accepts requests.</td></tr>
<tr>
<td>host</td><td>The hostname of the broker.</td></tr>
<tr>
<td>security_protocol_type</td><td>The security protocol type.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>UpdateMetadata Response (Version: 0) => error_code
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
</table>
</p>
<p><pre>UpdateMetadata Response (Version: 1) => error_code
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td>Error code.</td></tr>
</table>
</p>
<h4>ControlledShutdown API (Key: 7):</h4>
<b>Requests:</b><br>
</p>
<p><pre>ControlledShutdown Request (Version: 1) => broker_id
broker_id => INT32
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>broker_id</td><td>The id of the broker for which controlled shutdown has been requested.</td></tr>
</table>
</p>
<b>Responses:</b><br>
</p>
<p><pre>ControlledShutdown Response (Version: 1) => error_code [partitions_remaining]
partitions_remaining => topic partition
topic => STRING
partition => INT32
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>partitions_remaining</td><td>The partitions that the broker still leads.</td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
</table>
</p>
<h4>OffsetCommit API (Key: 8):</h4>
<b>Requests:</b><br>
<p><pre>OffsetCommit Request (Version: 0) => group_id [topics]
topics => topic [partitions]
partitions => partition offset metadata
partition => INT32
offset => INT64
metadata => STRING
topic => STRING
group_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>topics</td><td>Topics to commit offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to commit.</td></tr>
<tr>
<td>partitions</td><td>Partitions to commit offsets.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>offset</td><td>Message offset to be committed.</td></tr>
<tr>
<td>metadata</td><td>Any associated metadata the client wants to keep.</td></tr>
</table>
</p>
<p><pre>OffsetCommit Request (Version: 1) => group_id group_generation_id member_id [topics]
topics => topic [partitions]
partitions => partition offset timestamp metadata
partition => INT32
offset => INT64
timestamp => INT64
metadata => STRING
topic => STRING
group_id => STRING
group_generation_id => INT32
member_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>group_generation_id</td><td>The generation of the group.</td></tr>
<tr>
<td>member_id</td><td>The member id assigned by the group coordinator.</td></tr>
<tr>
<td>topics</td><td>Topics to commit offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to commit.</td></tr>
<tr>
<td>partitions</td><td>Partitions to commit offsets.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>offset</td><td>Message offset to be committed.</td></tr>
<tr>
<td>timestamp</td><td>Timestamp of the commit</td></tr>
<tr>
<td>metadata</td><td>Any associated metadata the client wants to keep.</td></tr>
</table>
</p>
<p><pre>OffsetCommit Request (Version: 2) => group_id group_generation_id member_id retention_time [topics]
topics => topic [partitions]
partitions => partition offset metadata
partition => INT32
offset => INT64
metadata => STRING
topic => STRING
group_id => STRING
group_generation_id => INT32
member_id => STRING
retention_time => INT64
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>group_generation_id</td><td>The generation of the consumer group.</td></tr>
<tr>
<td>member_id</td><td>The consumer id assigned by the group coordinator.</td></tr>
<tr>
<td>retention_time</td><td>Time period in ms to retain the offset.</td></tr>
<tr>
<td>topics</td><td>Topics to commit offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to commit.</td></tr>
<tr>
<td>partitions</td><td>Partitions to commit offsets.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>offset</td><td>Message offset to be committed.</td></tr>
<tr>
<td>metadata</td><td>Any associated metadata the client wants to keep.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>OffsetCommit Response (Version: 0) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code
partition => INT32
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<p><pre>OffsetCommit Response (Version: 1) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code
partition => INT32
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<p><pre>OffsetCommit Response (Version: 2) => [responses]
responses => topic [partition_responses]
partition_responses => partition error_code
partition => INT32
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<h4>OffsetFetch API (Key: 9):</h4>
<b>Requests:</b><br>
<p><pre>OffsetFetch Request (Version: 0) => group_id [topics]
topics => topic [partitions]
partitions => partition
partition => INT32
topic => STRING
group_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The consumer group id.</td></tr>
<tr>
<td>topics</td><td>Topics to fetch offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to fetch offset.</td></tr>
<tr>
<td>partitions</td><td>Partitions to fetch offsets.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
</table>
</p>
<p><pre>OffsetFetch Request (Version: 1) => group_id [topics]
topics => topic [partitions]
partitions => partition
partition => INT32
topic => STRING
group_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The consumer group id.</td></tr>
<tr>
<td>topics</td><td>Topics to fetch offsets.</td></tr>
<tr>
<td>topic</td><td>Topic to fetch offset.</td></tr>
<tr>
<td>partitions</td><td>Partitions to fetch offsets.</td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>OffsetFetch Response (Version: 0) => [responses]
responses => topic [partition_responses]
partition_responses => partition offset metadata error_code
partition => INT32
offset => INT64
metadata => STRING
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>offset</td><td>Last committed message offset.</td></tr>
<tr>
<td>metadata</td><td>Any associated metadata the client wants to keep.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<p><pre>OffsetFetch Response (Version: 1) => [responses]
responses => topic [partition_responses]
partition_responses => partition offset metadata error_code
partition => INT32
offset => INT64
metadata => STRING
error_code => INT16
topic => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>responses</td><td></td></tr>
<tr>
<td>topic</td><td></td></tr>
<tr>
<td>partition_responses</td><td></td></tr>
<tr>
<td>partition</td><td>Topic partition id.</td></tr>
<tr>
<td>offset</td><td>Last committed message offset.</td></tr>
<tr>
<td>metadata</td><td>Any associated metadata the client wants to keep.</td></tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<h4>GroupCoordinator API (Key: 10):</h4>
<b>Requests:</b><br>
<p><pre>GroupCoordinator Request (Version: 0) => group_id
group_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The unique group id.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>GroupCoordinator Response (Version: 0) => error_code coordinator
coordinator => node_id host port
node_id => INT32
host => STRING
port => INT32
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>coordinator</td><td>Host and port information for the coordinator for a consumer group.</td></tr>
<tr>
<td>node_id</td><td>The broker id.</td></tr>
<tr>
<td>host</td><td>The hostname of the broker.</td></tr>
<tr>
<td>port</td><td>The port on which the broker accepts requests.</td></tr>
</table>
</p>
<h4>JoinGroup API (Key: 11):</h4>
<b>Requests:</b><br>
<p><pre>JoinGroup Request (Version: 0) => group_id session_timeout member_id protocol_type [group_protocols]
group_protocols => protocol_name protocol_metadata
protocol_name => STRING
protocol_metadata => BYTES
group_id => STRING
session_timeout => INT32
member_id => STRING
protocol_type => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>session_timeout</td><td>The coordinator considers the consumer dead if it receives no heartbeat after this timeout in ms.</td></tr>
<tr>
<td>member_id</td><td>The assigned consumer id or an empty string for a new consumer.</td></tr>
<tr>
<td>protocol_type</td><td>Unique name for class of protocols implemented by group</td></tr>
<tr>
<td>group_protocols</td><td>List of protocols that the member supports</td></tr>
<tr>
<td>protocol_name</td><td></td></tr>
<tr>
<td>protocol_metadata</td><td></td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>JoinGroup Response (Version: 0) => error_code generation_id group_protocol leader_id member_id [members]
members => member_id member_metadata
member_id => STRING
member_metadata => BYTES
error_code => INT16
generation_id => INT32
group_protocol => STRING
leader_id => STRING
member_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>generation_id</td><td>The generation of the consumer group.</td></tr>
<tr>
<td>group_protocol</td><td>The group protocol selected by the coordinator</td></tr>
<tr>
<td>leader_id</td><td>The leader of the group</td></tr>
<tr>
<td>member_id</td><td>The consumer id assigned by the group coordinator.</td></tr>
<tr>
<td>members</td><td></td></tr>
<tr>
<td>member_id</td><td></td></tr>
<tr>
<td>member_metadata</td><td></td></tr>
</table>
</p>
<h4>Heartbeat API (Key: 12):</h4>
<b>Requests:</b><br>
<p><pre>Heartbeat Request (Version: 0) => group_id group_generation_id member_id
group_id => STRING
group_generation_id => INT32
member_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>group_generation_id</td><td>The generation of the group.</td></tr>
<tr>
<td>member_id</td><td>The member id assigned by the group coordinator.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>Heartbeat Response (Version: 0) => error_code
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<h4>LeaveGroup API (Key: 13):</h4>
<b>Requests:</b><br>
<p><pre>LeaveGroup Request (Version: 0) => group_id member_id
group_id => STRING
member_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td>The group id.</td></tr>
<tr>
<td>member_id</td><td>The member id assigned by the group coordinator.</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>LeaveGroup Response (Version: 0) => error_code
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
</table>
</p>
<h4>SyncGroup API (Key: 14):</h4>
<b>Requests:</b><br>
<p><pre>SyncGroup Request (Version: 0) => group_id generation_id member_id [group_assignment]
group_assignment => member_id member_assignment
member_id => STRING
member_assignment => BYTES
group_id => STRING
generation_id => INT32
member_id => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_id</td><td></td></tr>
<tr>
<td>generation_id</td><td></td></tr>
<tr>
<td>member_id</td><td></td></tr>
<tr>
<td>group_assignment</td><td></td></tr>
<tr>
<td>member_id</td><td></td></tr>
<tr>
<td>member_assignment</td><td></td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>SyncGroup Response (Version: 0) => error_code member_assignment
error_code => INT16
member_assignment => BYTES
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>member_assignment</td><td></td></tr>
</table>
</p>
<h4>DescribeGroups API (Key: 15):</h4>
<b>Requests:</b><br>
<p><pre>DescribeGroups Request (Version: 0) => [group_ids]
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>group_ids</td><td>List of groupIds to request metadata for (an empty groupId array will return empty group metadata).</td></tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>DescribeGroups Response (Version: 0) => [groups]
groups => error_code group_id state protocol_type protocol [members]
members => member_id client_id client_host member_metadata member_assignment
member_id => STRING
client_id => STRING
client_host => STRING
member_metadata => BYTES
member_assignment => BYTES
error_code => INT16
group_id => STRING
state => STRING
protocol_type => STRING
protocol => STRING
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>groups</td><td></td></tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>group_id</td><td></td></tr>
<tr>
<td>state</td><td>The current state of the group (one of: Dead, Stable, AwaitingSync, or PreparingRebalance, or empty if there is no active group)</td></tr>
<tr>
<td>protocol_type</td><td>The current group protocol type (will be empty if the there is no active group)</td></tr>
<tr>
<td>protocol</td><td>The current group protocol (only provided if the group is Stable)</td></tr>
<tr>
<td>members</td><td>Current group members (only provided if the group is not Dead)</td></tr>
<tr>
<td>member_id</td><td>The memberId assigned by the coordinator</td></tr>
<tr>
<td>client_id</td><td>The client id used in the member's latest join group request</td></tr>
<tr>
<td>client_host</td><td>The client host used in the request session corresponding to the member's join group.</td></tr>
<tr>
<td>member_metadata</td><td>The metadata corresponding to the current group protocol in use (will only be present if the group is stable).</td></tr>
<tr>
<td>member_assignment</td><td>The current assignment provided by the group leader (will only be present if the group is stable).</td></tr>
</table>
</p>
<h4>ListGroups API (Key: 16):</h4>
<b>Requests:</b><br>
<p><pre>ListGroups Request (Version: 0) =>
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
</table>
</p>
<b>Responses:</b><br>
<p><pre>ListGroups Response (Version: 0) => error_code [groups]
groups => group_id protocol_type
group_id => STRING
protocol_type => STRING
error_code => INT16
</pre><table class="data-table"><tbody>
<tr>
<th>Field</th>
<th>Description</th>
</tr>
<tr>
<td>error_code</td><td></td></tr>
<tr>
<td>groups</td><td></td></tr>
<tr>
<td>group_id</td><td></td></tr>
<tr>
<td>protocol_type</td><td></td></tr>
</table>
</p>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment