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

EventGridv2 TypeSpec Api Preview #23204

Merged
merged 38 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
68f887b
start typespec
l0lawrence Mar 17, 2023
6554c10
adding eventgrid typespec for api w/ TODOs
l0lawrence Mar 20, 2023
eb98a20
update eventgrid typespec with latest eventgrid v2 operations
Mar 22, 2023
c879030
don't require content-type if there is no body
l0lawrence Mar 23, 2023
6b989da
Update specification/eventgrid/typespec/main.tsp
lmazuel Mar 24, 2023
4a5f9cf
Update specification/eventgrid/typespec/main.tsp
lmazuel Mar 24, 2023
5511313
changing naming of cloudevent and added in data_base64
l0lawrence Mar 24, 2023
1a56614
openapi.json
l0lawrence Mar 24, 2023
c724eed
Update specification/eventgrid/typespec/main.tsp
lmazuel Mar 24, 2023
f91ee18
Update specification/eventgrid/typespec/main.tsp
lmazuel Mar 24, 2023
eb01ed4
Update specification/eventgrid/typespec/main.tsp
lmazuel Mar 24, 2023
69ccc41
lockTokens format, updated json, optional? params
l0lawrence Mar 25, 2023
0d2cb3a
changes
l0lawrence Mar 25, 2023
c2d4c68
address code review comments
ahamad-MS Mar 28, 2023
36d0e06
Merge branch 'feature/eventgrid/typespec' of https://github.com/Azure…
ahamad-MS Mar 28, 2023
15dccec
name_change
l0lawrence Apr 12, 2023
13f6949
add @internal for python
l0lawrence Apr 12, 2023
069bafb
Update specification/eventgrid/Azure.Messaging.EventGrid/main.tsp
l0lawrence Apr 12, 2023
5d21632
move @internal to client.tsp (#23538)
l0lawrence Apr 13, 2023
17fd291
rename (#23565)
l0lawrence Apr 14, 2023
663b348
[EventGrid Typespec] breaking changes with april release of typespec …
l0lawrence Apr 14, 2023
fd1fd9d
[EG Typespec] Update Release behavior (#23699)
l0lawrence Apr 24, 2023
02ea7de
Add tspconfig and remove AAD auth (#23717)
JoshLove-msft Apr 25, 2023
17d65e2
Merge branch 'main' of https://github.com/Azure/azure-rest-api-specs …
l0lawrence Apr 25, 2023
3806bc1
[EG TypeSpec] Archboard Comments (#23696)
l0lawrence Apr 26, 2023
799d10c
Address couple of stewardship team feedback. These include: 1. Rename…
ahamad-MS Apr 28, 2023
10e0e8c
Add support for missing Reject operation + adding deliveryAttemptCoun…
ahamad-MS Apr 29, 2023
09f9244
Update failedTokens/SuccessfulTokens Description to address code revi…
ahamad-MS May 1, 2023
6c2b560
Update to match service behavior (#23754)
JoshLove-msft May 1, 2023
20958fd
[EGv2] Editing unused variables (#23917)
l0lawrence May 10, 2023
16602df
Merge branch 'main' of https://github.com/Azure/azure-rest-api-specs …
l0lawrence May 11, 2023
911c47f
[EGv2] Version dependency on Azure.Core (#23936)
l0lawrence May 11, 2023
418e39a
[EventGrid] Deliveryattempt change (#23960)
l0lawrence May 12, 2023
e570388
[EventGrid] Remove internal (#23995)
l0lawrence May 16, 2023
0b24c89
remove waitWaitTime (#24078)
l0lawrence May 19, 2023
a90210c
move location of json file (#24076)
l0lawrence May 19, 2023
d1c21b5
[Egv2] Encode param (#24080)
l0lawrence May 22, 2023
4b1d4a0
[EGv2] Fix pipeline (#24098)
l0lawrence May 22, 2023
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
10 changes: 10 additions & 0 deletions specification/eventgrid/Azure.Messaging.EventGrid/client.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import "@azure-tools/typespec-client-generator-core";
import "./main.tsp";

using Azure.ClientGenerator.Core;

@@internal(Azure.Messaging.EventGrid.CloudEventEvent);
@@internal(Azure.Messaging.EventGrid.ReceiveDetails);
@@internal(Azure.Messaging.EventGrid.PublishBatchOfCloudEvents);
@@internal(Azure.Messaging.EventGrid.PublishCloudEvent);
@@internal(Azure.Messaging.EventGrid.ReceiveBatchOfCloudEvents);
236 changes: 236 additions & 0 deletions specification/eventgrid/Azure.Messaging.EventGrid/main.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import "@typespec/http";
import "@typespec/rest";
import "@typespec/versioning";
import "@azure-tools/typespec-autorest";
import "@azure-tools/typespec-azure-core";

enum ServiceApiVersions {
v2023_06_01_preview: "2023-06-01-preview"
}

@useAuth(
ApiKeyAuth<ApiKeyLocation.header, "SharedAccessKey"> | OAuth2Auth<[{
type: OAuth2FlowType.implicit,
authorizationUrl: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
scopes: ["https://eventgrid.azure.net/.default"],
}]>
)

@service({
title: "Azure.Messaging.EventGridMessagingClient",
version: "2023-06-01-preview"
})

//
// Supported operations.
//
// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}:publish?api-version={apiVersion}}
// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:receive?api-Version={apiVersion}&timeout=60&maxEvents={maxEvents}
// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:acknowledge?api-Version={apiVersion}
// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:release?api-version={apiVersion}
//

@server(
"{endpoint}",
"The host name of the topic",
{
@doc("The host name of the namespace, e.g. namespaceName1.westus-1.eventgrid.azure.net")
endpoint: url,
}
)

@doc("Azure Messaging EventGrid Client")
@versioned(ServiceApiVersions)
namespace Azure.Messaging.EventGrid {
using TypeSpec.Http;
using TypeSpec.Rest;
using TypeSpec.Versioning;
using Azure.Core;
using Azure.Core.Foundations;

@doc("Properties of an event published to an Azure Messaging EventGrid Namespace topic using the CloudEvent 1.0 Schema.")
model CloudEventEvent {
@doc("An identifier for the event. The combination of id and source must be unique for each distinct event.")
id: string;

@doc("Identifies the context in which an event happened. The combination of id and source must be unique for each distinct event.")
source: string;

@doc("Event data specific to the event type.")
data?: object;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed to unknown?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


@doc("Event data specific to the event type, encoded as a base64 string.")
data_base64?: bytes;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, and directly below, we prefer camelCase for property names and enum values.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is following the outside spec of CloudEvent, it requires these parameters to be lowercase


@doc("Type of event related to the originating occurrence.")
type: string;

@doc("The time (in UTC) the event was generated, in RFC3339 format.")
time?: zonedDateTime;

@doc("The version of the CloudEvents specification which the event uses.")
specversion: string;

@doc("Identifies the schema that data adheres to.")
dataschema?: string;

@doc("Content type of data value.")
datacontenttype?: string;

@doc("This describes the subject of the event in the context of the event producer (identified by source).")
subject?: string;
}

@doc("LockToken information.")
model LockToken {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't have the model and property name be the same thing. Can this be called something like LockTokenProperties?

Copy link
Member

@JoshLove-msft JoshLove-msft Apr 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, possibly too late for the initial preview, but I really wonder whether it is worth having this model vs simply defining the lockToken as a string on each of the containing models. In my mind, the lock token is self sufficient and any supplementary information that might be added in the future may be context-dependent and can be added to the container model. Especially considering we don't even use this model for both input and output (only output).

@doc("The token used to lock the event.")
lockToken: string;
}

@doc("Properties of the Event Broker operation.")
model BrokerProperties {
@doc("The token used to lock the event.")
lockToken: LockToken;
}

@doc("Receive operation details per Cloud Event.")
model ReceiveDetails {
@doc("The Event Broker details.")
brokerProperties: BrokerProperties;

@doc("Cloud Event details.")
event: CloudEventEvent;
}

@doc("Details of the Receive operation response.")
model ReceiveResponse {
@doc("Array of receive responses, one per cloud event.")
value: ReceiveDetails[];
}

@doc("Failed LockToken information.")
model FailedLockToken {
@doc("LockToken value")
lockToken: LockToken;

@doc("Error code")
errorCode: int32;

@doc("Description of the error")
errorDescription: string;
}

@doc("Details of the LockTokens information. This is used for both Acknowledge and Release operation response.")
model LockTokensResponse {
JoshLove-msft marked this conversation as resolved.
Show resolved Hide resolved
@doc("Array of LockToken values for failed cloud events.")
failedLockTokens: FailedLockToken[];

@doc("Array of LockToken values for succeeded cloud events.")
succeededLockTokens: string[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does failedLockTokens have a type of FailedLockToken but succeededLockTokens have type string? Either one of these is typed incorrectly or one of them is not an array of "LockTokens" as the name suggests.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FailedLockToken contains additional information - the errorCode and errorDescription. So the docs need updating to clarify that it is an array of FailedLockToken values.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating the docs is certainly welcome, but I think some users will still find the naming confusing.

A "LockToken" is a string. A "succeededLockToken" is a LockToken (string) that succeeded. A "failedLockToken" is not a LockToken that failed -- it is a completely different type.

Rather than "failedLockToken", I think a better name would be "LockTokenFailure" -- since it describes the failure for a lock token. Is it too late to make a name change?

Copy link
Member

@JoshLove-msft JoshLove-msft May 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not really a LockTokenFailure - it's a failure in one of the settlement operations (acknowledge or release), and the lock tokens that can be used to correlate the failures with the events that were received via the receive operations are included in the payload.

Maybe something like "failureInformation"?

}

@doc("Lock token input formatting.")
model LockTokenInput {
@doc("LockTokens")
lockTokens: string[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this string array rather than LockToken array?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the LockToken type is meant for output that might evolve over time.

}

// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}:publish?api-version={apiVersion}}

@doc("Publish Single Cloud Event to namespace topic.")
@route("/topics/{topicName}:publish", {shared: true})
@post op PublishCloudEvent is Azure.Core.RpcOperation<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not a collection action of a Topic resource?

@doc("content type")
@header("content-type")
contentType: "application/cloudevents+json; charset=utf-8";

@doc("Topic Name.")
@path
topicName: string;

@doc("Single Cloud Event being published.")
@body
event: CloudEventEvent;
}, OkResponse>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From testing the server, we indeed receive a 200. We would have expected a 204, not a 200, given this returns no body.



@doc("Publish Batch of Cloud Events to namespace topic.")
@route("/topics/{topicName}:publish", {shared: true})
@post op PublishBatchOfCloudEvents is Azure.Core.RpcOperation<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@post op PublishBatchOfCloudEvents is Azure.Core.RpcOperation<{
@post op PublishCloudEvents is Azure.Core.RpcOperation<{

@doc("content type")
@header("content-type")
contentType: "application/cloudevents-batch+json; charset=utf-8";

@doc("Topic Name.")
@path
topicName: string;

@doc("Array of Cloud Events being published.")
@body
events: CloudEventEvent[];
}, OkResponse>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before:
From testing the server, we indeed receive a 200. We would have expected a 204, not a 200, given this returns no body.


@doc("Receive Batch of Cloud Events from the Event Subscription.")
@route("/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:receive")
@post op ReceiveBatchOfCloudEvents is Azure.Core.RpcOperation<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not a collection action over an EventSubscription resource?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@post op ReceiveBatchOfCloudEvents is Azure.Core.RpcOperation<{
@post op ReceiveCloudEvents is Azure.Core.RpcOperation<{

@doc("Topic Name.")
@path
topicName: string;

@doc("Event Subscription Name.")
@path
eventSubscriptionName: string;

@doc("Max Events count to be received.")
@query
maxEvents?: int32 = 1;

@doc("Timeout value for receive operation in Seconds. Default is 60 seconds.")
@query
timeout?: int32 =60;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we wanted to name this as maxWaitTime - is there a way to do that given this is query param sent to the service?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some format we can apply so this generates as a TimeSpan,Duration,etc? In swagger, we would use format: date-time.

Copy link
Member Author

@l0lawrence l0lawrence Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think projected name can be used here for renaming

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, is there an equivalent for format: date-time?

Copy link
Member

@lmazuel lmazuel Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there some format we can apply so this generates as a TimeSpan,Duration,etc? In swagger, we would use format: date-time.

Type it as duration. We're still working on specifiying that the serialization format is an int, so let's keep int for now short term

Copy link
Member

@lmazuel lmazuel Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we wanted to name this as maxWaitTime - is there a way to do that given this is query param sent to the service?

alias Parameters = {
@query({name:"bad-name-on-wire"})
CoolName: string;
};

op foo(...Parameters): void;

}, ReceiveResponse & CreatedResponse >;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we see calling the service, is that nothing to receive returns an empty list with a 200, and if there are events this is a 201


// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:acknowledge&apiVersion={apiVersion}

@doc("Acknowledge Cloud Events.")
@route("/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:acknowledge")
@post op AcknowledgeBatchOfCloudEvents is Azure.Core.RpcOperation<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@post op AcknowledgeBatchOfCloudEvents is Azure.Core.RpcOperation<{
@post op AcknowledgeCloudEvents is Azure.Core.RpcOperation<{

@doc("content type")
@header("content-type")
contentType: "application/json; charset=utf-8";

@doc("Topic Name.")
@path
topicName: string;

@doc("Event Subscription Name.")
@path
eventSubscriptionName: string;

@doc("Array of LockTokens for the corresponding received Cloud Events to be acknowledged.")
@body
lockTokens: LockTokenInput;
}, LockTokensResponse >;

// POST https://{namespaceName}.{region}.eventgrid.azure.net/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:release?api-version={apiVersion}

@doc("Release Cloud Events.")
@route("/topics/{topicName}/eventsubscriptions/{eventSubscriptionName}:release")
@post op ReleaseBatchOfCloudEvents is Azure.Core.RpcOperation<{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
@post op ReleaseBatchOfCloudEvents is Azure.Core.RpcOperation<{
@post op ReleaseCloudEvents is Azure.Core.RpcOperation<{

@doc("content type")
@header("content-type")
contentType: "application/json; charset=utf-8";

@doc("Topic Name.")
@path
topicName: string;

@doc("Event Subscription Name.")
@path
eventSubscriptionName: string;

@doc("Array of LockTokens for the corresponding received Cloud Events to be acknowledged.")
@body
tokens : LockToken[];
}, LockTokensResponse >;
}
Loading