Skip to content

Commit

Permalink
Merge pull request #88 from supabase/return-objects-not-arrays
Browse files Browse the repository at this point in the history
API responses now always return objects and never arrays
  • Loading branch information
imor authored Feb 5, 2025
2 parents 047a822 + 56ad677 commit cc91f84
Show file tree
Hide file tree
Showing 13 changed files with 101 additions and 32 deletions.
12 changes: 9 additions & 3 deletions api/src/routes/images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ pub struct GetImageResponse {
is_default: bool,
}

#[derive(Serialize, ToSchema)]
pub struct GetImagesResponse {
images: Vec<GetImageResponse>,
}

#[utoipa::path(
context_path = "/v1",
request_body = PostImageRequest,
Expand Down Expand Up @@ -178,14 +183,15 @@ pub async fn delete_image(
)]
#[get("/images")]
pub async fn read_all_images(pool: Data<PgPool>) -> Result<impl Responder, ImageError> {
let mut sources = vec![];
let mut images = vec![];
for image in db::images::read_all_images(&pool).await? {
let image = GetImageResponse {
id: image.id,
name: image.name,
is_default: image.is_default,
};
sources.push(image);
images.push(image);
}
Ok(Json(sources))
let response = GetImagesResponse { images };
Ok(Json(response))
}
12 changes: 9 additions & 3 deletions api/src/routes/pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ pub struct GetPipelineResponse {
config: PipelineConfig,
}

#[derive(Serialize, ToSchema)]
pub struct GetPipelinesResponse {
pipelines: Vec<GetPipelineResponse>,
}

#[utoipa::path(
context_path = "/v1",
request_body = PostPipelineRequest,
Expand Down Expand Up @@ -319,7 +324,7 @@ pub async fn read_all_pipelines(
let mut pipelines = vec![];
for pipeline in db::pipelines::read_all_pipelines(&pool, tenant_id).await? {
let config: PipelineConfig = serde_json::from_value(pipeline.config)?;
let sink = GetPipelineResponse {
let pipeline = GetPipelineResponse {
id: pipeline.id,
tenant_id: pipeline.tenant_id,
source_id: pipeline.source_id,
Expand All @@ -330,9 +335,10 @@ pub async fn read_all_pipelines(
publication_name: pipeline.publication_name,
config,
};
pipelines.push(sink);
pipelines.push(pipeline);
}
Ok(Json(pipelines))
let response = GetPipelinesResponse { pipelines };
Ok(Json(response))
}

#[utoipa::path(
Expand Down
8 changes: 7 additions & 1 deletion api/src/routes/sinks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ pub struct GetSinkResponse {
config: SinkConfig,
}

#[derive(Serialize, ToSchema)]
pub struct GetSinksResponse {
sinks: Vec<GetSinkResponse>,
}

#[utoipa::path(
context_path = "/v1",
request_body = PostSinkRequest,
Expand Down Expand Up @@ -229,5 +234,6 @@ pub async fn read_all_sinks(
};
sinks.push(sink);
}
Ok(Json(sinks))
let response = GetSinksResponse { sinks };
Ok(Json(response))
}
8 changes: 7 additions & 1 deletion api/src/routes/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ pub struct GetSourceResponse {
config: SourceConfig,
}

#[derive(Serialize, ToSchema)]
pub struct GetSourcesResponse {
sources: Vec<GetSourceResponse>,
}

#[utoipa::path(
context_path = "/v1",
request_body = PostSourceRequest,
Expand Down Expand Up @@ -231,5 +236,6 @@ pub async fn read_all_sources(
};
sources.push(source);
}
Ok(Json(sources))
let response = GetSourcesResponse { sources };
Ok(Json(response))
}
11 changes: 8 additions & 3 deletions api/src/routes/sources/publications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use actix_web::{
web::{Data, Json, Path},
HttpRequest, HttpResponse, Responder, ResponseError,
};
use serde::Deserialize;
use serde::{Deserialize, Serialize};
use sqlx::PgPool;
use thiserror::Error;
use utoipa::ToSchema;
Expand Down Expand Up @@ -81,6 +81,11 @@ pub struct UpdatePublicationRequest {
tables: Vec<Table>,
}

#[derive(Serialize, ToSchema)]
pub struct GetPublicationsResponse {
pub publications: Vec<Publication>,
}

#[utoipa::path(
context_path = "/v1",
request_body = CreatePublicationRequest,
Expand Down Expand Up @@ -251,6 +256,6 @@ pub async fn read_all_publications(

let options = config.connect_options();
let publications = db::publications::read_all_publications(&options).await?;

Ok(Json(publications))
let response = GetPublicationsResponse { publications };
Ok(Json(response))
}
13 changes: 10 additions & 3 deletions api/src/routes/sources/tables.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ use actix_web::{
web::{Data, Json, Path},
HttpRequest, HttpResponse, Responder, ResponseError,
};
use serde::Serialize;
use sqlx::PgPool;
use thiserror::Error;
use utoipa::ToSchema;

use crate::{
db::{self, sources::SourcesDbError},
db::{self, sources::SourcesDbError, tables::Table},
encryption::EncryptionKey,
routes::{extract_tenant_id, ErrorMessage, TenantIdError},
};
Expand Down Expand Up @@ -39,6 +41,11 @@ impl TableError {
}
}

#[derive(Serialize, ToSchema)]
pub struct GetTablesReponse {
pub tables: Vec<Table>,
}

impl ResponseError for TableError {
fn status_code(&self) -> StatusCode {
match self {
Expand Down Expand Up @@ -89,6 +96,6 @@ pub async fn read_table_names(

let options = config.connect_options();
let tables = db::tables::get_tables(&options).await?;

Ok(Json(tables))
let response = GetTablesReponse { tables };
Ok(Json(response))
}
8 changes: 7 additions & 1 deletion api/src/routes/tenants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ pub struct GetTenantResponse {
name: String,
}

#[derive(Serialize, ToSchema)]
pub struct GetTenantsResponse {
tenants: Vec<GetTenantResponse>,
}

#[utoipa::path(
context_path = "/v1",
request_body = CreateTenantRequest,
Expand Down Expand Up @@ -206,13 +211,14 @@ pub async fn delete_tenant(
)]
#[get("/tenants")]
pub async fn read_all_tenants(pool: Data<PgPool>) -> Result<impl Responder, TenantError> {
let response: Vec<GetTenantResponse> = db::tenants::read_all_tenants(&pool)
let tenants: Vec<GetTenantResponse> = db::tenants::read_all_tenants(&pool)
.await?
.drain(..)
.map(|t| GetTenantResponse {
id: t.id,
name: t.name,
})
.collect();
let response = GetTenantsResponse { tenants };
Ok(Json(response))
}
7 changes: 4 additions & 3 deletions api/tests/api/images.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use reqwest::StatusCode;

use crate::test_app::{
spawn_app, CreateImageRequest, CreateImageResponse, ImageResponse, TestApp, UpdateImageRequest,
spawn_app, CreateImageRequest, CreateImageResponse, ImageResponse, ImagesResponse, TestApp,
UpdateImageRequest,
};

pub async fn create_default_image(app: &TestApp) -> i64 {
Expand Down Expand Up @@ -191,11 +192,11 @@ async fn all_images_can_be_read() {

// Assert
assert!(response.status().is_success());
let response: Vec<ImageResponse> = response
let response: ImagesResponse = response
.json()
.await
.expect("failed to deserialize response");
for image in response {
for image in response.images {
if image.id == image1_id {
assert_eq!(image.name, "some/image");
assert!(image.is_default);
Expand Down
8 changes: 4 additions & 4 deletions api/tests/api/pipelines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::{
tenants::create_tenant,
tenants::create_tenant_with_id_and_name,
test_app::{
spawn_app, CreatePipelineRequest, CreatePipelineResponse, PipelineResponse, TestApp,
UpdatePipelineRequest,
spawn_app, CreatePipelineRequest, CreatePipelineResponse, PipelineResponse,
PipelinesResponse, TestApp, UpdatePipelineRequest,
},
};

Expand Down Expand Up @@ -439,11 +439,11 @@ async fn all_pipelines_can_be_read() {

// Assert
assert!(response.status().is_success());
let response: Vec<PipelineResponse> = response
let response: PipelinesResponse = response
.json()
.await
.expect("failed to deserialize response");
for pipeline in response {
for pipeline in response.pipelines {
if pipeline.id == pipeline1_id {
let config = new_pipeline_config();
assert_eq!(&pipeline.tenant_id, tenant_id);
Expand Down
7 changes: 4 additions & 3 deletions api/tests/api/sinks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use reqwest::StatusCode;
use crate::{
tenants::create_tenant,
test_app::{
spawn_app, CreateSinkRequest, CreateSinkResponse, SinkResponse, TestApp, UpdateSinkRequest,
spawn_app, CreateSinkRequest, CreateSinkResponse, SinkResponse, SinksResponse, TestApp,
UpdateSinkRequest,
},
};

Expand Down Expand Up @@ -225,11 +226,11 @@ async fn all_sinks_can_be_read() {

// Assert
assert!(response.status().is_success());
let response: Vec<SinkResponse> = response
let response: SinksResponse = response
.json()
.await
.expect("failed to deserialize response");
for sink in response {
for sink in response.sinks {
if sink.id == sink1_id {
let name = new_name();
let config = new_sink_config();
Expand Down
8 changes: 4 additions & 4 deletions api/tests/api/sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use reqwest::StatusCode;
use crate::{
tenants::create_tenant,
test_app::{
spawn_app, CreateSourceRequest, CreateSourceResponse, SourceResponse, TestApp,
UpdateSourceRequest,
spawn_app, CreateSourceRequest, CreateSourceResponse, SourceResponse, SourcesResponse,
TestApp, UpdateSourceRequest,
},
};

Expand Down Expand Up @@ -235,11 +235,11 @@ async fn all_sources_can_be_read() {

// Assert
assert!(response.status().is_success());
let response: Vec<SourceResponse> = response
let response: SourcesResponse = response
.json()
.await
.expect("failed to deserialize response");
for source in response {
for source in response.sources {
if source.id == source1_id {
let name = new_name();
let config = new_source_config();
Expand Down
6 changes: 3 additions & 3 deletions api/tests/api/tenants.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use reqwest::StatusCode;

use crate::test_app::{
spawn_app, CreateTenantRequest, CreateTenantResponse, TenantResponse, TestApp,
spawn_app, CreateTenantRequest, CreateTenantResponse, TenantResponse, TenantsResponse, TestApp,
UpdateTenantRequest,
};

Expand Down Expand Up @@ -267,11 +267,11 @@ async fn all_tenants_can_be_read() {

// Assert
assert!(response.status().is_success());
let response: Vec<TenantResponse> = response
let response: TenantsResponse = response
.json()
.await
.expect("failed to deserialize response");
for tenant in response {
for tenant in response.tenants {
if tenant.id == tenant1_id {
assert_eq!(tenant.name, "Tenant1");
} else if tenant.id == tenant2_id {
Expand Down
25 changes: 25 additions & 0 deletions api/tests/api/test_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ pub struct TenantResponse {
pub name: String,
}

#[derive(Deserialize)]
pub struct TenantsResponse {
pub tenants: Vec<TenantResponse>,
}

#[derive(Serialize)]
pub struct CreateSourceRequest {
pub name: String,
Expand All @@ -65,6 +70,11 @@ pub struct SourceResponse {
pub config: SourceConfig,
}

#[derive(Deserialize)]
pub struct SourcesResponse {
pub sources: Vec<SourceResponse>,
}

#[derive(Serialize)]
pub struct CreateSinkRequest {
pub name: String,
Expand All @@ -90,6 +100,11 @@ pub struct SinkResponse {
pub config: SinkConfig,
}

#[derive(Deserialize)]
pub struct SinksResponse {
pub sinks: Vec<SinkResponse>,
}

#[derive(Serialize)]
pub struct CreatePipelineRequest {
pub source_id: i64,
Expand All @@ -114,6 +129,11 @@ pub struct PipelineResponse {
pub config: PipelineConfig,
}

#[derive(Deserialize)]
pub struct PipelinesResponse {
pub pipelines: Vec<PipelineResponse>,
}

#[derive(Serialize)]
pub struct UpdatePipelineRequest {
pub source_id: i64,
Expand All @@ -140,6 +160,11 @@ pub struct ImageResponse {
pub is_default: bool,
}

#[derive(Deserialize)]
pub struct ImagesResponse {
pub images: Vec<ImageResponse>,
}

#[derive(Serialize)]
pub struct UpdateImageRequest {
pub name: String,
Expand Down

0 comments on commit cc91f84

Please sign in to comment.