Skip to content

Commit

Permalink
[Connector API] Improve create connector endpoints (#108766)
Browse files Browse the repository at this point in the history
  • Loading branch information
jedrazb committed May 17, 2024
1 parent 458e147 commit bb5cac9
Show file tree
Hide file tree
Showing 17 changed files with 291 additions and 320 deletions.
9 changes: 5 additions & 4 deletions docs/reference/connector/apis/create-connector-api.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ DELETE _connector/my-connector

[[create-connector-api-request]]
==== {api-request-title}
`POST _connector`
* `POST _connector`

`PUT _connector/<connector_id>`
* `PUT _connector/<connector_id>`


[[create-connector-api-prereqs]]
Expand All @@ -54,7 +54,7 @@ Creates a connector document in the internal index and initializes its configura
==== {api-path-parms-title}

`<connector_id>`::
(Required, string) Unique identifier of a connector.
(Optional, string) Unique identifier of a connector.


[role="child_attributes"]
Expand Down Expand Up @@ -123,7 +123,8 @@ The API returns the following result:
[source,console-result]
----
{
"result": "created"
"result": "created",
"id": "my-connector"
}
----
////
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"body": {
"description": "The connector configuration.",
"required": true
"required": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@
"description": "The unique identifier of the connector to be created or updated."
}
}
},
{
"path": "/_connector",
"methods": [
"PUT"
]
}
]
},
"body": {
"description": "The connector configuration.",
"required": true
"required": false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,40 @@ setup:
is_native: false
service_type: super-connector

---
'Create Connector - Id returned as part of response':
- do:
connector.put:
connector_id: test-connector-1
body:
index_name: search-test

- match: { result: 'created' }
- match: { id: test-connector-1 }

---
'Create Connector - Succeeds if body not provided':
- do:
connector.put:
connector_id: test-connector-1

- match: { result: 'created' }
- match: { id: test-connector-1 }


---
'Create Connector - Succeeds if body not provided and id not provided':
- do:
connector.put: { }

- set: { id: id }
- match: { id: $id }

- do:
connector.get:
connector_id: $id

- match: { id: $id }

---
'Create Connector - Index name used by another connector':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,20 @@ setup:
- match: { is_native: false }
- match: { service_type: super-connector }

---
'Create Connector - Succeeds if body not provided':
- do:
connector.post: { }

- set: { id: id }
- match: { id: $id }

- do:
connector.get:
connector_id: $id

- match: { id: $id }

---
'Create Connector - Default values are initialized correctly':
- do:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentType;
import org.elasticsearch.xpack.application.connector.action.PostConnectorAction;
import org.elasticsearch.xpack.application.connector.action.PutConnectorAction;
import org.elasticsearch.xpack.application.connector.action.ConnectorCreateActionResponse;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorApiKeyIdAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorConfigurationAction;
import org.elasticsearch.xpack.application.connector.action.UpdateConnectorErrorAction;
Expand Down Expand Up @@ -96,25 +95,28 @@ public ConnectorIndexService(Client client) {
}

/**
* Creates or updates the {@link Connector} in the underlying index with a specific doc ID.
*
* @param request Request for creating the connector.
* Creates or updates the {@link Connector} in the underlying index with a specific doc ID
* if connectorId is provided. Otherwise, the connector doc is indexed with auto-generated doc ID.
* @param connectorId The id of the connector object. If null, id will be auto-generated.
* @param description The description of the connector.
* @param indexName The name of the index associated with the connector. It can be null to indicate that index is not attached yet.
* @param isNative Flag indicating if the connector is native; defaults to false if null.
* @param language The language supported by the connector.
* @param name The name of the connector; defaults to an empty string if null.
* @param serviceType The type of service the connector integrates with.
* @param listener The action listener to invoke on response/failure.
*/
public void createConnectorWithDocId(PutConnectorAction.Request request, ActionListener<DocWriteResponse> listener) {

String indexName = request.getIndexName();
String connectorId = request.getConnectorId();

Connector connector = createConnectorWithDefaultValues(
request.getDescription(),
request.getIndexName(),
request.getIsNative(),
request.getLanguage(),
request.getName(),
request.getServiceType()
);

public void createConnector(
String connectorId,
String description,
String indexName,
Boolean isNative,
String language,
String name,
String serviceType,
ActionListener<ConnectorCreateActionResponse> listener
) {
Connector connector = createConnectorWithDefaultValues(description, indexName, isNative, language, name, serviceType);
try {
isDataIndexNameAlreadyInUse(indexName, connectorId, listener.delegateFailure((l, isIndexNameInUse) -> {
if (isIndexNameInUse) {
Expand All @@ -127,62 +129,20 @@ public void createConnectorWithDocId(PutConnectorAction.Request request, ActionL
return;
}
try {
final IndexRequest indexRequest = new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX)
.id(connectorId)
IndexRequest indexRequest = new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX)
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.source(connector.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS));
client.index(indexRequest, listener);
} catch (Exception e) {
listener.onFailure(e);
}
}));
} catch (Exception e) {
listener.onFailure(e);
}
}

/**
* Creates or updates the {@link Connector} in the underlying index with an auto-generated doc ID.
*
* @param request Request for creating the connector.
* @param listener The action listener to invoke on response/failure.
*/
public void createConnectorWithAutoGeneratedId(
PostConnectorAction.Request request,
ActionListener<PostConnectorAction.Response> listener
) {

String indexName = request.getIndexName();

Connector connector = createConnectorWithDefaultValues(
request.getDescription(),
indexName,
request.getIsNative(),
request.getLanguage(),
request.getName(),
request.getServiceType()
);

try {
isDataIndexNameAlreadyInUse(indexName, null, listener.delegateFailure((l, isIndexNameInUse) -> {
if (isIndexNameInUse) {
l.onFailure(
new ElasticsearchStatusException(
"Index name [" + indexName + "] is used by another connector.",
RestStatus.BAD_REQUEST
)
);
return;
}
try {
final IndexRequest indexRequest = new IndexRequest(CONNECTOR_INDEX_NAME).opType(DocWriteRequest.OpType.INDEX)
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
.source(connector.toXContent(jsonBuilder(), ToXContent.EMPTY_PARAMS));
if (Strings.isNullOrEmpty(connectorId) == false) {
indexRequest = indexRequest.id(connectorId);
}

client.index(
indexRequest,
listener.delegateFailureAndWrap(
(ll, indexResponse) -> ll.onResponse(new PostConnectorAction.Response(indexResponse.getId()))
(ll, indexResponse) -> ll.onResponse(
new ConnectorCreateActionResponse(indexResponse.getId(), indexResponse.getResult())
)
)
);
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.application.connector.action;

import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xcontent.ToXContentObject;
import org.elasticsearch.xcontent.XContentBuilder;

import java.io.IOException;
import java.util.Objects;

public class ConnectorCreateActionResponse extends ActionResponse implements ToXContentObject {

private final String id;
private final DocWriteResponse.Result result;

public ConnectorCreateActionResponse(StreamInput in) throws IOException {
super(in);
this.id = in.readString();
this.result = DocWriteResponse.Result.readFrom(in);
}

public ConnectorCreateActionResponse(String id, DocWriteResponse.Result result) {
this.id = id;
this.result = result;
}

public String getId() {
return id;
}

public DocWriteResponse.Result getResult() {
return result;
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(id);
result.writeTo(out);
}

@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.field("id", this.id);
builder.field("result", this.result.getLowercase());
builder.endObject();
return builder;
}

public RestStatus status() {
return switch (result) {
case CREATED -> RestStatus.CREATED;
case NOT_FOUND -> RestStatus.NOT_FOUND;
default -> RestStatus.OK;
};
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConnectorCreateActionResponse that = (ConnectorCreateActionResponse) o;
return Objects.equals(id, that.id) && result == that.result;
}

@Override
public int hashCode() {
return Objects.hash(id, result);
}
}
Loading

0 comments on commit bb5cac9

Please sign in to comment.