Skip to content

Commit

Permalink
feat: interest registration endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
smrz2001 committed Jan 28, 2024
1 parent 393b876 commit 7a3b8d8
Show file tree
Hide file tree
Showing 11 changed files with 533 additions and 68 deletions.
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

0 comments on commit 7a3b8d8

Please sign in to comment.