Skip to content

Commit 12567e6

Browse files
feat: add apiresource
1 parent ce9a2fa commit 12567e6

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

apiresource/apiresource.go

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Package apiresource implements an API resource management as described in
2+
// https://brandur.org/two-phase-render
3+
package apiresource
4+
5+
import (
6+
"context"
7+
"fmt"
8+
)
9+
10+
type Renderable[TBundle any, TEntity any, TResource any, TParams any] interface {
11+
Bundle(context.Context, TParams, []TEntity) (TBundle, error)
12+
Render(context.Context, TParams, TBundle, TEntity) (TResource, error)
13+
}
14+
15+
// Render renders an API resource.
16+
func Render[
17+
TRenderable Renderable[TBundle, TEntity, TRenderable, TParams],
18+
TBundle any,
19+
TEntity any,
20+
TParams any,
21+
](
22+
ctx context.Context,
23+
params TParams,
24+
entity TEntity,
25+
) (TRenderable, error) {
26+
var renderable TRenderable
27+
28+
bundle, err := renderable.Bundle(ctx, params, []TEntity{entity})
29+
if err != nil {
30+
return renderable, fmt.Errorf("apiresource: error loading bundle: %w", err)
31+
}
32+
33+
resource, err := renderable.Render(ctx, params, bundle, entity)
34+
if err != nil {
35+
return renderable, fmt.Errorf("apiresource: error rendering resource: %w", err)
36+
}
37+
38+
return resource, nil
39+
}
40+
41+
// RenderMany is similar to Render, but renders many API resources at once.
42+
func RenderMany[
43+
TBundle any,
44+
TRenderable Renderable[TBundle, TEntity, TRenderable, TParams],
45+
TEntity any,
46+
TParams any,
47+
](
48+
ctx context.Context,
49+
params TParams,
50+
entities []TEntity,
51+
) ([]TRenderable, error) {
52+
var renderable TRenderable
53+
54+
bundle, err := renderable.Bundle(ctx, params, entities)
55+
if err != nil {
56+
return nil, fmt.Errorf("apiresource: error loading bundle: %w", err)
57+
}
58+
59+
resources := make([]TRenderable, len(entities))
60+
for i := range resources {
61+
resources[i], err = renderable.Render(ctx, params, bundle, entities[i])
62+
if err != nil {
63+
return nil, fmt.Errorf("apiresource: error rendering resource: %w", err)
64+
}
65+
}
66+
67+
return resources, nil
68+
}

0 commit comments

Comments
 (0)