+106
README.md
+106
README.md
···
1
+
2
+
`atwork-cli`: basic demo tool for interacting with `at://work`
3
+
===============================================================
4
+
5
+
`at://work` (https://atwork.place) is a job board build using AT ([atproto](https://atproto.com)).
6
+
7
+
This little CLI project is really a demo/tutorial for AT developer tools, including [indigo](https://github.com/bluesky-social/indigo) (the Go SDK) and [glot](https://tangled.org/bnewbold.net/cobalt/tree/main/cmd/glot) (lexicon management and codegen for Go).
8
+
9
+
10
+
## Project Setup Tutorial
11
+
12
+
In the context of this little CLI project, we are going to work with existing Lexicons, instead of declaring our own. These Lexicons span several namespaces, and not all of them have maintained public SDKs for Go.
13
+
14
+
We'll use [gloat](https://tangled.org/bnewbold.net/cobalt/tree/main/cmd/glot) to work with published lexicons, though note a bunch of glot functionality is expected to get merged in to the `goat` command soon.
15
+
16
+
Starting in an empty project directory, and with `glot` installed, we'll start by pulling down the `place.atwork.*` Lexicons. The trailing `.` in this command tells it to fetch all schemas under the Lexicon group:
17
+
18
+
```
19
+
$ glot pull place.atwork.
20
+
๐ข place.atwork.searchListings
21
+
๐ข place.atwork.profile
22
+
๐ข place.atwork.listing
23
+
๐ข place.atwork.getListings
24
+
๐ข place.atwork.getListing
25
+
๐ข place.atwork.endorsementProof
26
+
๐ข place.atwork.endorsement
27
+
28
+
```
29
+
30
+
Next we'll initialize the Go project, and try to generate types for these Lexicons:
31
+
32
+
```
33
+
$ go mod init tangled.org/bnewbold.net/atwork-cli
34
+
go: creating new go.mod: module tangled.org/bnewbold.net/atwork-cli
35
+
36
+
$ glot codegen lexicons/place/atwork --output-dir .
37
+
๐ lexicons/place/atwork/endorsement.json
38
+
[failed]: failed to format codegen output (lexicons/place/atwork/endorsement.json): could not resolve lexicon reference (com.atproto.repo.strongRef): schema not found in catalog: com.atproto.repo.strongRef#main
39
+
๐ข lexicons/place/atwork/endorsementProof.json
40
+
๐ข lexicons/place/atwork/getListing.json
41
+
๐ข lexicons/place/atwork/getListings.json
42
+
๐ lexicons/place/atwork/listing.json
43
+
[failed]: failed to format codegen output (lexicons/place/atwork/listing.json): could not resolve lexicon reference (app.bsky.richtext.facet): schema not found in catalog: app.bsky.richtext.facet#main
44
+
๐ lexicons/place/atwork/profile.json
45
+
[failed]: failed to format codegen output (lexicons/place/atwork/profile.json): could not resolve lexicon reference (app.bsky.richtext.facet): schema not found in catalog: app.bsky.richtext.facet#main
46
+
๐ข lexicons/place/atwork/searchListings.json
47
+
error: some codegen failed
48
+
```
49
+
50
+
This hits some errors because the Lexicons reference other namespaces (`lexicons.community.*`, `app.bsky.richtext.*`, `com.atproto.repo.strongRef`). In the future these might get pulled in automatically, but for now let's pull them in to our namespace:
51
+
52
+
```
53
+
$ glot pull app.bsky.richtext.facet community.lexicon.location.hthree com.atproto.repo.strongRef
54
+
๐ข app.bsky.richtext.facet
55
+
๐ข community.lexicon.location.hthree
56
+
๐ข com.atproto.repo.strongRef
57
+
```
58
+
59
+
The `app.bsky.*` namespace has a published Go package, and the `com.atproto.*` namespace is protocol-level, but `lexicons.community.*` doesn't have package, so we'll generate code for that Lexicon as well:
60
+
61
+
```
62
+
$ glot codegen lexicons/place/atwork lexicons/community/lexicon --output-dir .
63
+
๐ข lexicons/community/lexicon/location/hthree.json
64
+
๐ข lexicons/place/atwork/endorsement.json
65
+
๐ข lexicons/place/atwork/endorsementProof.json
66
+
๐ข lexicons/place/atwork/getListing.json
67
+
๐ข lexicons/place/atwork/getListings.json
68
+
๐ข lexicons/place/atwork/listing.json
69
+
๐ข lexicons/place/atwork/profile.json
70
+
๐ข lexicons/place/atwork/searchListings.json
71
+
```
72
+
73
+
Great, now we have generated types for all the Lexicons we use.
74
+
75
+
76
+
## Basic API Request: Search
77
+
78
+
The `place.atwork.*` lexicons include both record types and API endpoints. Let's try calling an unauthenticated public API endpoint using the indigo API client.
79
+
80
+
```go
81
+
// pseudo-code; see main.go for actual implementation
82
+
83
+
import (
84
+
"github.com/bluesky-social/indigo/atproto/atclient"
85
+
"tangled.org/bnewbold.net/atwork-cli/placeatwork"
86
+
)
87
+
88
+
func main() {
89
+
90
+
searchQuery := "intern"
91
+
apiServer := "https://atwork.place"
92
+
93
+
client := atclient.NewAPIClient(apiServer)
94
+
95
+
resp, err := placeatwork.SearchListings(ctx, client, searchQuery)
96
+
if err != nil {
97
+
return err
98
+
}
99
+
100
+
for _, hit := range resp.Listings {
101
+
fmt.Prinln(hit.Value.Title)
102
+
}
103
+
}
104
+
```
105
+
106
+
The API client gets injected in to the generated API endpoint code (`placeatwork.SearchListings`), which converts the response JSON into the expected struct type.