Bind KV and Workers via API

Is there a way to bind a worker and a KV namespace directly through the API? I can create a worker, I can create a namespace, and I can GET the binding from the namespace, all via the API. It seems silly that I wouldn’t be able to connect the two.

1 Like

Yes - in the PUT script [1] api call, you can include a bindings array to link environment vars, secrets, kv namespaces etc. There is no good documentation about this on the cloudflare api doc page, but it is informally described here [2].

The binding object for kv namespace linking is of the form:
{ "type": "kv_namespace", "name": "myGlobalVarName", "namespace_id": "myNamespaceId" }

[1] https://api.cloudflare.com/#worker-script-upload-worker
[2] https://developers.cloudflare.com/workers/platform/scripts#upload-or-update-a-workers-script

1 Like

Thanks for the reply, John! I had seen that binding object in the docs. Where I’m hung up is getting that object to the API in the PUT call. I’ve tried embedding that object directly in the script string, as its own payload in application/json (content-type error) and application/javascript (parsing error) calls, and as a part in a multipart/form-data call, which yields various 10021 errors, the last of which being “could not read content for part metadata”.

In the various attempts, I’ve tried sending that object formatted as a standalone object, as well as wrapping it in a { "bindings": [ bindingObject ] } object.

Appreciate your help with this!

It will depend on what you’re using to make the http calls, below I’ve included the relevant snippet for what I do in my java-based cloudflare api client.

It’s been a while since I looked at this, but iirc the multipart names are important as well - hence perhaps why you’re getting “could not read content for part metadata”.

Hope that helps,
- John

MultipartBody.Builder b = new MultipartBody.Builder()
        .setType(MultipartBody.FORM);
JSONObject metadata = Util.newJsonObj("body_part", "script");
JSONArray bindingsArr = new JSONArray();
for (Binding binding : bindings) {
    if (binding.isPlainText() || binding.isSecretText()) {
        JSONObject bindingObj = Util.newJsonObj("type", binding.type, "name", binding.name);
        if (binding.text != null) {
            bindingObj.put("text", binding.text);
        }
        bindingsArr.put(bindingObj);
    } else if (binding.isKvNamespace()) {
        JSONObject bindingObj = Util.newJsonObj("type", binding.type, "name", binding.name, "namespace_id", binding.namespaceId);
        bindingsArr.put(bindingObj);
    } else {
        throw new UnsupportedOperationException(binding.type);
    }
}
metadata.put("bindings", bindingsArr);
b.addFormDataPart("metadata", null, RequestBody.create(C.ContentType.APPLICATION_JSON, Util.toSortedJson(metadata)));
b.addFormDataPart("script", null, RequestBody.create(C.ContentType.APPLICATION_JAVASCRIPT, ByteString.encodeUtf8(script)));
MultipartBody multipartBody = b.build();
ByteString requestBodyBytes = Util.requestBodyBytes(multipartBody);
r.body(multipartBody.contentType(), requestBodyBytes);
2 Likes

John, you’re my hero! That’s exactly what I needed. Thanks!

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.