fix(api): 400 for non-object connection config + null workflow graph; 409 for duplicate connection name
This commit is contained in:
@@ -29,10 +29,21 @@ public static class ConnectionsEndpoints
|
||||
|
||||
g.MapPost("", (CreateConnectionRequest req, ConnectionRepository repo, IConnectionSecretPolicy policy) =>
|
||||
{
|
||||
var id = repo.Create(req.ProviderId, req.Name, req.Config.GetRawText());
|
||||
var stripped = StripSecrets(req.Config.GetRawText(), policy.SecretFieldsFor(req.ProviderId));
|
||||
return Results.Created($"/api/connections/{id}",
|
||||
new ConnectionResponse(id, req.ProviderId, req.Name, stripped));
|
||||
if (req.Config.ValueKind != JsonValueKind.Object)
|
||||
return Results.BadRequest(new { error = "config must be a JSON object" });
|
||||
|
||||
try
|
||||
{
|
||||
var id = repo.Create(req.ProviderId, req.Name, req.Config.GetRawText());
|
||||
var stripped = StripSecrets(req.Config.GetRawText(), policy.SecretFieldsFor(req.ProviderId));
|
||||
return Results.Created($"/api/connections/{id}",
|
||||
new ConnectionResponse(id, req.ProviderId, req.Name, stripped));
|
||||
}
|
||||
catch (Microsoft.Data.Sqlite.SqliteException ex) when (ex.SqliteErrorCode == 19)
|
||||
{
|
||||
// SQLITE_CONSTRAINT — unique index on (provider_id, name).
|
||||
return Results.Conflict(new { error = "a connection with that name already exists for this provider" });
|
||||
}
|
||||
});
|
||||
|
||||
g.MapDelete("/{id}", (string id, ConnectionRepository repo) =>
|
||||
|
||||
@@ -21,14 +21,22 @@ public static class WorkflowsEndpoints
|
||||
|
||||
g.MapPost("", (CreateWorkflowRequest req, WorkflowRepository repo) =>
|
||||
{
|
||||
if (req.Graph.ValueKind is JsonValueKind.Undefined or JsonValueKind.Null)
|
||||
return Results.BadRequest(new { error = "graph is required" });
|
||||
|
||||
var id = repo.Create(req.Name, req.Graph.GetRawText());
|
||||
var w = repo.Get(id)!;
|
||||
return Results.Created($"/api/workflows/{id}", ToDto(w));
|
||||
});
|
||||
|
||||
g.MapPut("/{id}", (string id, UpdateWorkflowRequest req, WorkflowRepository repo) =>
|
||||
repo.Update(id, req.Name, req.Graph.GetRawText())
|
||||
? Results.NoContent() : Results.NotFound());
|
||||
{
|
||||
if (req.Graph.ValueKind is JsonValueKind.Undefined or JsonValueKind.Null)
|
||||
return Results.BadRequest(new { error = "graph is required" });
|
||||
|
||||
return repo.Update(id, req.Name, req.Graph.GetRawText())
|
||||
? Results.NoContent() : Results.NotFound();
|
||||
});
|
||||
|
||||
g.MapPost("/{id}/activate", (string id, WorkflowRepository repo) =>
|
||||
repo.SetActive(id, true) ? Results.NoContent() : Results.NotFound());
|
||||
|
||||
@@ -46,5 +46,33 @@ public class ConnectionsEndpointsTests : IClassFixture<WebFactory>
|
||||
Assert.DoesNotContain(list2!, x => x.Id == created.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Post_with_non_object_config_returns_400()
|
||||
{
|
||||
var c = await LoggedIn();
|
||||
var res = await c.PostAsJsonAsync("/api/connections", new
|
||||
{
|
||||
providerId = "nats", name = "x", config = "not-an-object"
|
||||
});
|
||||
Assert.Equal(HttpStatusCode.BadRequest, res.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Post_with_duplicate_name_per_provider_returns_409()
|
||||
{
|
||||
var c = await LoggedIn();
|
||||
var first = await c.PostAsJsonAsync("/api/connections", new
|
||||
{
|
||||
providerId = "nats", name = "dup", config = new { url = "nats://x" }
|
||||
});
|
||||
Assert.Equal(HttpStatusCode.Created, first.StatusCode);
|
||||
|
||||
var second = await c.PostAsJsonAsync("/api/connections", new
|
||||
{
|
||||
providerId = "nats", name = "dup", config = new { url = "nats://y" }
|
||||
});
|
||||
Assert.Equal(HttpStatusCode.Conflict, second.StatusCode);
|
||||
}
|
||||
|
||||
private sealed record ConnectionDto(string Id, string ProviderId, string Name, JsonElement Config);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,14 @@ public class WorkflowsEndpointsTests : IClassFixture<WebFactory>
|
||||
Assert.Equal(HttpStatusCode.NotFound, missing.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Post_with_missing_graph_returns_400()
|
||||
{
|
||||
var c = await LoggedIn();
|
||||
var res = await c.PostAsJsonAsync("/api/workflows", new { name = "nograph" });
|
||||
Assert.Equal(HttpStatusCode.BadRequest, res.StatusCode);
|
||||
}
|
||||
|
||||
private sealed record WorkflowDto(string Id, string Name, bool Active,
|
||||
System.Text.Json.JsonElement Graph, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user