Skip to content
This repository was archived by the owner on Sep 3, 2024. It is now read-only.

Commit 20e11e6

Browse files
serving up hyper shcma + schema forms embedded in the resource
1 parent 2c634ea commit 20e11e6

10 files changed

Lines changed: 159 additions & 12 deletions

src/SqlStreamStore.HAL/Constants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public static class Relations
3131
public const string Feed = "streamStore:feed";
3232
public const string Message = "streamStore:message";
3333
public const string Metadata = "streamStore:metadata";
34+
public const string AppendToStream = "streamStore:append";
3435
}
3536

3637
public static class Streams

src/SqlStreamStore.HAL/Resources/AllStreamResource.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ public async Task<Response> GetPage(
6666
payload,
6767
metadata = message.JsonMetadata
6868
})
69-
.AddLinks(Links.Message.Self(message)))));
69+
.AddLinks(Links.Message.Self(message))))
70+
);
7071

7172
if(operation.FromPositionInclusive == Position.End)
7273
{

src/SqlStreamStore.HAL/Resources/AppendStreamOperation.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,34 +51,44 @@ private AppendStreamOperation(HttpRequest request, JObject body)
5151
: this(request, new JArray { body })
5252
{ }
5353

54-
private static NewStreamMessage ParseNewStreamMessage(JToken newStreamMessage, int index)
54+
private static NewStreamMessageDto ParseNewStreamMessage(JToken newStreamMessage, int index)
5555
{
5656
if(!Guid.TryParse(newStreamMessage.Value<string>("messageId"), out var messageId))
5757
{
58-
throw new InvalidAppendRequestException($"'{nameof(messageId)}' at index {index} was improperly formatted.");
58+
throw new InvalidAppendRequestException(
59+
$"'{nameof(messageId)}' at index {index} was improperly formatted.");
5960
}
61+
6062
if(messageId == Guid.Empty)
6163
{
6264
throw new InvalidAppendRequestException($"'{nameof(messageId)}' at index {index} was empty.");
6365
}
66+
6467
var type = newStreamMessage.Value<string>("type");
6568

6669
if(type == null)
6770
{
6871
throw new InvalidAppendRequestException($"'{nameof(type)}' at index {index} was not set.");
6972
}
70-
71-
return new NewStreamMessage(
72-
messageId,
73-
type,
74-
newStreamMessage.Value<JToken>("jsonData").ToString(),
75-
newStreamMessage.Value<JToken>("jsonMetadata")?.ToString());
73+
74+
return new NewStreamMessageDto
75+
{
76+
MessageId = messageId,
77+
Type = type,
78+
JsonData = newStreamMessage.Value<JToken>("jsonData"),
79+
JsonMetadata = newStreamMessage.Value<JToken>("jsonMetadata")
80+
};
7681
}
82+
7783
public string StreamId { get; }
7884
public int ExpectedVersion { get; }
79-
public NewStreamMessage[] NewStreamMessages { get; }
85+
public NewStreamMessageDto[] NewStreamMessages { get; }
8086

81-
public Task<AppendResult> Invoke(IStreamStore streamStore, CancellationToken ct)
82-
=> streamStore.AppendToStream(StreamId, ExpectedVersion, NewStreamMessages, ct);
87+
public Task<AppendResult> Invoke(IStreamStore streamStore, CancellationToken ct)
88+
=> streamStore.AppendToStream(
89+
StreamId,
90+
ExpectedVersion,
91+
Array.ConvertAll(NewStreamMessages, dto => dto.ToNewStreamMessage()),
92+
ct);
8393
}
8494
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace SqlStreamStore.HAL.Resources
2+
{
3+
using System;
4+
using Newtonsoft.Json.Linq;
5+
using SqlStreamStore.Streams;
6+
7+
internal class NewStreamMessageDto
8+
{
9+
public Guid MessageId { get; set; }
10+
public string Type { get; set; }
11+
public JToken JsonData { get; set; }
12+
public JToken JsonMetadata { get; set; }
13+
14+
public NewStreamMessage ToNewStreamMessage()
15+
=> new NewStreamMessage(MessageId, Type, JsonData.ToString(), JsonMetadata?.ToString());
16+
}
17+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
3+
"title": "Append to Stream",
4+
"type": "object",
5+
"required": [
6+
"messageId",
7+
"type"
8+
],
9+
"properties": {
10+
"messageId": {
11+
"type": "string",
12+
"pattern": "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$"
13+
},
14+
"type": {
15+
"type": "string"
16+
},
17+
"jsonData": {
18+
"type": "object",
19+
"x-schema-form": {
20+
"key": "jsonData",
21+
"type": "textarea",
22+
"rows": 30
23+
}
24+
},
25+
"jsonMetadata": {
26+
"type": "object",
27+
"x-schema-form": {
28+
"key": "jsonMetadata",
29+
"type": "textarea",
30+
"rows": 30
31+
}
32+
}
33+
},
34+
"$form": [
35+
"messageId",
36+
"type",
37+
{
38+
"key": "jsonData",
39+
"type": "textarea"
40+
},
41+
{
42+
"key": "jsonMetadata",
43+
"type": "textarea"
44+
}
45+
]
46+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"type": "object",
3+
"$schema": "http://json-schema.org/draft-07/hyper-schema#",
4+
"properties": {
5+
"maxCount": {
6+
"type": "integer",
7+
"minimum": 1
8+
},
9+
"maxAge": {
10+
"type": "integer",
11+
"minimum": 1
12+
},
13+
"metadataJson": {
14+
"type": "object"
15+
}
16+
}
17+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace SqlStreamStore.HAL.Resources
2+
{
3+
using System;
4+
using System.Collections.Concurrent;
5+
using System.IO;
6+
using System.Reflection;
7+
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Linq;
9+
10+
internal static class Schemas
11+
{
12+
private static readonly ConcurrentDictionary<string, JObject> s_schemas
13+
= new ConcurrentDictionary<string, JObject>();
14+
15+
public static JObject AppendToStream => GetSchema(nameof(AppendToStream));
16+
public static JObject SetStreamMetadata => GetSchema(nameof(SetStreamMetadata));
17+
18+
private static JObject GetSchema(string name) => s_schemas.GetOrAdd(name, ReadSchema);
19+
20+
private static JObject ReadSchema(string name)
21+
{
22+
using(Stream stream = typeof(Schemas)
23+
.GetTypeInfo().Assembly
24+
.GetManifestResourceStream(typeof(Schemas), $"Schema.{name}.json"))
25+
{
26+
if(stream == null)
27+
{
28+
throw new Exception($"Embedded resource, {name}, not found. BUG!");
29+
}
30+
31+
using(var reader = new JsonTextReader(new StreamReader(stream)))
32+
{
33+
return JObject.Load(reader);
34+
}
35+
}
36+
}
37+
}
38+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace SqlStreamStore.HAL.Resources
2+
{
3+
using Newtonsoft.Json.Linq;
4+
5+
internal class SetStreamMetadataDto
6+
{
7+
public JToken MetadataJson { get; set; }
8+
public int? MaxCount { get; set; }
9+
public int? MaxAge { get; set; }
10+
}
11+
}

src/SqlStreamStore.HAL/Resources/StreamResource.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public async Task<Response> GetPage(ReadStreamOperation operation, CancellationT
7575
.AddLinks(Links.Navigation(page, operation))
7676
.AddLinks(Links.Feed(operation))
7777
.AddLinks(Links.Metadata(operation))
78+
.AddEmbeddedResource(
79+
Constants.Relations.AppendToStream,
80+
new HALResponse(Schemas.AppendToStream))
7881
.AddEmbeddedCollection(
7982
Constants.Relations.Message,
8083
streamMessages.Zip(

src/SqlStreamStore.HAL/SqlStreamStore.HAL.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@
1212
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
1313
<PackageReference Include="SqlStreamStore" Version="1.1.2" />
1414
</ItemGroup>
15+
<ItemGroup>
16+
<EmbeddedResource Include="Resources\Schema\*.json" />
17+
</ItemGroup>
1518
</Project>

0 commit comments

Comments
 (0)