lexicon devex tutorial

write README

Changed files
+106
+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.