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

feat: interest registration endpoint #246

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
4 changes: 3 additions & 1 deletion api-server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ To see how to make this your own, look here:
[README]((https://openapi-generator.tech))

- API version: 0.9.0
- Build date: 2024-01-24T14:39:40.257161505-07:00[America/Denver]
- Build date: 2024-01-28T18:51:47.756188-05:00[America/New_York]



Expand Down Expand Up @@ -62,6 +62,7 @@ cargo run --example server
To run a client, follow one of the following simple steps:

```
cargo run --example client InterestsSortKeySortValuePost
cargo run --example client LivenessGet
cargo run --example client SubscribeSortKeySortValueGet
cargo run --example client VersionPost
Expand Down Expand Up @@ -99,6 +100,7 @@ All URIs are relative to */ceramic*
Method | HTTP request | Description
------------- | ------------- | -------------
[****](docs/default_api.md#) | **POST** /events | Creates a new event
[****](docs/default_api.md#) | **POST** /interests/{sort_key}/{sort_value} | Register interest for a sort key
[****](docs/default_api.md#) | **GET** /liveness | Test the liveness of the Ceramic node
[****](docs/default_api.md#) | **GET** /subscribe/{sort_key}/{sort_value} | Get events for a stream
[****](docs/default_api.md#) | **POST** /version | Get the version of the Ceramic node
Expand Down
39 changes: 39 additions & 0 deletions api-server/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,45 @@ paths:
"204":
description: success
summary: Creates a new event
/interests/{sort_key}/{sort_value}:
post:
parameters:
- description: name of the sort_key
explode: false
in: path
name: sort_key
required: true
schema:
type: string
style: simple
- description: value associated with the sort key
explode: false
in: path
name: sort_value
required: true
schema:
type: string
style: simple
- description: the controller to register interest for
explode: true
in: query
name: controller
required: false
schema:
type: string
style: form
- description: the stream to register interest for
explode: true
in: query
name: streamId
required: false
schema:
type: string
style: form
responses:
"204":
description: success
summary: Register interest for a sort key
components:
requestBodies:
Event:
Expand Down
38 changes: 38 additions & 0 deletions api-server/docs/default_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All URIs are relative to */ceramic*
Method | HTTP request | Description
------------- | ------------- | -------------
****](default_api.md#) | **POST** /events | Creates a new event
****](default_api.md#) | **POST** /interests/{sort_key}/{sort_value} | Register interest for a sort key
****](default_api.md#) | **GET** /liveness | Test the liveness of the Ceramic node
****](default_api.md#) | **GET** /subscribe/{sort_key}/{sort_value} | Get events for a stream
****](default_api.md#) | **POST** /version | Get the version of the Ceramic node
Expand Down Expand Up @@ -35,6 +36,43 @@ No authorization required

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# ****
> (sort_key, sort_value, optional)
Register interest for a sort key

### Required Parameters

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**sort_key** | **String**| name of the sort_key |
**sort_value** | **String**| value associated with the sort key |
**optional** | **map[string]interface{}** | optional parameters | nil if no parameters

### Optional Parameters
Optional parameters are passed through a map[string]interface{}.

Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------
**sort_key** | **String**| name of the sort_key |
**sort_value** | **String**| value associated with the sort key |
**controller** | **String**| the controller to register interest for |
**stream_id** | **String**| the stream to register interest for |

### Return type

(empty response body)

### Authorization

No authorization required

### HTTP request headers

- **Content-Type**: Not defined
- **Accept**: Not defined

[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)

# ****
> ()
Test the liveness of the Ceramic node
Expand Down
23 changes: 21 additions & 2 deletions api-server/examples/client/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#[allow(unused_imports)]
use ceramic_api_server::{
models, Api, ApiNoContext, Client, ContextWrapperExt, EventsPostResponse, LivenessGetResponse,
models, Api, ApiNoContext, Client, ContextWrapperExt, EventsPostResponse,
InterestsSortKeySortValuePostResponse, LivenessGetResponse,
SubscribeSortKeySortValueGetResponse, VersionPostResponse,
};
use clap::{App, Arg};
Expand Down Expand Up @@ -32,7 +33,12 @@ fn main() {
.arg(
Arg::with_name("operation")
.help("Sets the operation to run")
.possible_values(&["LivenessGet", "SubscribeSortKeySortValueGet", "VersionPost"])
.possible_values(&[
"InterestsSortKeySortValuePost",
"LivenessGet",
"SubscribeSortKeySortValueGet",
"VersionPost",
])
.required(true)
.index(1),
)
Expand Down Expand Up @@ -95,6 +101,19 @@ fn main() {
info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has<XSpanIdString>).get().clone());
},
*/
Some("InterestsSortKeySortValuePost") => {
let result = rt.block_on(client.interests_sort_key_sort_value_post(
"sort_key_example".to_string(),
"sort_value_example".to_string(),
Some("controller_example".to_string()),
Some("stream_id_example".to_string()),
));
info!(
"{:?} (X-Span-ID: {:?})",
result,
(client.context() as &dyn Has<XSpanIdString>).get().clone()
);
}
Some("LivenessGet") => {
let result = rt.block_on(client.liveness_get());
info!(
Expand Down
24 changes: 22 additions & 2 deletions api-server/examples/server/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ impl<C> Server<C> {

use ceramic_api_server::server::MakeService;
use ceramic_api_server::{
Api, EventsPostResponse, LivenessGetResponse, SubscribeSortKeySortValueGetResponse,
VersionPostResponse,
Api, EventsPostResponse, InterestsSortKeySortValuePostResponse, LivenessGetResponse,
SubscribeSortKeySortValueGetResponse, VersionPostResponse,
};
use std::error::Error;
use swagger::ApiError;
Expand All @@ -126,6 +126,26 @@ where
Err(ApiError("Generic failure".into()))
}

/// Register interest for a sort key
async fn interests_sort_key_sort_value_post(
&self,
sort_key: String,
sort_value: String,
controller: Option<String>,
stream_id: Option<String>,
context: &C,
) -> Result<InterestsSortKeySortValuePostResponse, ApiError> {
info!(
"interests_sort_key_sort_value_post(\"{}\", \"{}\", {:?}, {:?}) - X-Span-ID: {:?}",
sort_key,
sort_value,
controller,
stream_id,
context.get().0.clone()
);
Err(ApiError("Generic failure".into()))
}

/// Test the liveness of the Ceramic node
async fn liveness_get(&self, context: &C) -> Result<LivenessGetResponse, ApiError> {
info!("liveness_get() - X-Span-ID: {:?}", context.get().0.clone());
Expand Down
90 changes: 88 additions & 2 deletions api-server/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ const FRAGMENT_ENCODE_SET: &AsciiSet = &percent_encoding::CONTROLS
const ID_ENCODE_SET: &AsciiSet = &FRAGMENT_ENCODE_SET.add(b'|');

use crate::{
Api, EventsPostResponse, LivenessGetResponse, SubscribeSortKeySortValueGetResponse,
VersionPostResponse,
Api, EventsPostResponse, InterestsSortKeySortValuePostResponse, LivenessGetResponse,
SubscribeSortKeySortValueGetResponse, VersionPostResponse,
};

/// Convert input into a base path, e.g. "http://example:123". Also checks the scheme as it goes.
Expand Down Expand Up @@ -479,6 +479,92 @@ where
}
}

async fn interests_sort_key_sort_value_post(
&self,
param_sort_key: String,
param_sort_value: String,
param_controller: Option<String>,
param_stream_id: Option<String>,
context: &C,
) -> Result<InterestsSortKeySortValuePostResponse, ApiError> {
let mut client_service = self.client_service.clone();
let mut uri = format!(
"{}/ceramic/interests/{sort_key}/{sort_value}",
self.base_path,
sort_key = utf8_percent_encode(&param_sort_key.to_string(), ID_ENCODE_SET),
sort_value = utf8_percent_encode(&param_sort_value.to_string(), ID_ENCODE_SET)
);

// Query parameters
let query_string = {
let mut query_string = form_urlencoded::Serializer::new("".to_owned());
if let Some(param_controller) = param_controller {
query_string.append_pair("controller", &param_controller);
}
if let Some(param_stream_id) = param_stream_id {
query_string.append_pair("streamId", &param_stream_id);
}
query_string.finish()
};
if !query_string.is_empty() {
uri += "?";
uri += &query_string;
}

let uri = match Uri::from_str(&uri) {
Ok(uri) => uri,
Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))),
};

let mut request = match Request::builder()
.method("POST")
.uri(uri)
.body(Body::empty())
{
Ok(req) => req,
Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))),
};

let header = HeaderValue::from_str(Has::<XSpanIdString>::get(context).0.as_str());
request.headers_mut().insert(
HeaderName::from_static("x-span-id"),
match header {
Ok(h) => h,
Err(e) => {
return Err(ApiError(format!(
"Unable to create X-Span ID header value: {}",
e
)))
}
},
);

let response = client_service
.call((request, context.clone()))
.map_err(|e| ApiError(format!("No response received: {}", e)))
.await?;

match response.status().as_u16() {
204 => Ok(InterestsSortKeySortValuePostResponse::Success),
code => {
let headers = response.headers().clone();
let body = response.into_body().take(100).into_raw().await;
Err(ApiError(format!(
"Unexpected response code {}:\n{:?}\n\n{}",
code,
headers,
match body {
Ok(body) => match String::from_utf8(body) {
Ok(body) => body,
Err(e) => format!("<Body was not UTF8: {:?}>", e),
},
Err(e) => format!("<Failed to read body: {}>", e),
}
)))
}
}
}

async fn liveness_get(&self, context: &C) -> Result<LivenessGetResponse, ApiError> {
let mut client_service = self.client_service.clone();
let mut uri = format!("{}/ceramic/liveness", self.base_path);
Expand Down
41 changes: 41 additions & 0 deletions api-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ pub enum EventsPostResponse {
Success,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum InterestsSortKeySortValuePostResponse {
/// success
Success,
}

#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub enum LivenessGetResponse {
/// success
Expand Down Expand Up @@ -64,6 +70,16 @@ pub trait Api<C: Send + Sync> {
context: &C,
) -> Result<EventsPostResponse, ApiError>;

/// Register interest for a sort key
async fn interests_sort_key_sort_value_post(
&self,
sort_key: String,
sort_value: String,
controller: Option<String>,
stream_id: Option<String>,
context: &C,
) -> Result<InterestsSortKeySortValuePostResponse, ApiError>;

/// Test the liveness of the Ceramic node
async fn liveness_get(&self, context: &C) -> Result<LivenessGetResponse, ApiError>;

Expand Down Expand Up @@ -97,6 +113,15 @@ pub trait ApiNoContext<C: Send + Sync> {
/// Creates a new event
async fn events_post(&self, event: models::Event) -> Result<EventsPostResponse, ApiError>;

/// Register interest for a sort key
async fn interests_sort_key_sort_value_post(
&self,
sort_key: String,
sort_value: String,
controller: Option<String>,
stream_id: Option<String>,
) -> Result<InterestsSortKeySortValuePostResponse, ApiError>;

/// Test the liveness of the Ceramic node
async fn liveness_get(&self) -> Result<LivenessGetResponse, ApiError>;

Expand Down Expand Up @@ -146,6 +171,22 @@ impl<T: Api<C> + Send + Sync, C: Clone + Send + Sync> ApiNoContext<C> for Contex
self.api().events_post(event, &context).await
}

/// Register interest for a sort key
async fn interests_sort_key_sort_value_post(
&self,
sort_key: String,
sort_value: String,
controller: Option<String>,
stream_id: Option<String>,
) -> Result<InterestsSortKeySortValuePostResponse, ApiError> {
let context = self.context().clone();
self.api()
.interests_sort_key_sort_value_post(
sort_key, sort_value, controller, stream_id, &context,
)
.await
}

/// Test the liveness of the Ceramic node
async fn liveness_get(&self) -> Result<LivenessGetResponse, ApiError> {
let context = self.context().clone();
Expand Down
Loading
Loading