Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Connector API] Improve create connector endpoints #108766

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) -> {
efegurkan marked this conversation as resolved.
Show resolved Hide resolved
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) {
efegurkan marked this conversation as resolved.
Show resolved Hide resolved
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
Loading