Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pacedotdev/oto
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.8.0
Choose a base ref
...
head repository: pacedotdev/oto
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.9.0
Choose a head ref
  • 17 commits
  • 22 files changed
  • 4 contributors

Commits on Jul 26, 2020

  1. Added links to templates

    matryer authored Jul 26, 2020
    Copy the full SHA
    fd86ba8 View commit details
  2. clearer comment re Pace CLI

    matryer authored Jul 26, 2020
    Copy the full SHA
    00a1779 View commit details
  3. Update README.md

    matryer authored Jul 26, 2020
    Copy the full SHA
    b8b1e09 View commit details

Commits on Jul 27, 2020

  1. added docs for otohttp

    matryer committed Jul 27, 2020
    Copy the full SHA
    1a933a7 View commit details
  2. Copy the full SHA
    e4d7bee View commit details

Commits on Jul 28, 2020

  1. added Go client template

    matryer committed Jul 28, 2020
    Copy the full SHA
    3e384ae View commit details
  2. Created extractCommentMetadata function and added tests

    Seth Centerbar committed Jul 28, 2020
    Copy the full SHA
    da62ad3 View commit details

Commits on Jul 31, 2020

  1. Update README.md

    EwanValentine authored Jul 31, 2020
    Copy the full SHA
    62d198b View commit details

Commits on Aug 13, 2020

  1. Merge pull request #13 from sethcenterbar/support-comment-metadata

    Created extractCommentMetadata function and added tests
    matryer authored Aug 13, 2020
    Copy the full SHA
    12e1c85 View commit details
  2. only calculate regexp once

    matryer committed Aug 13, 2020
    Copy the full SHA
    7dd1f42 View commit details
  3. Merge pull request #14 from EwanValentine/EwanValentine-patch-1

    Update README.md
    matryer authored Aug 13, 2020
    Copy the full SHA
    884e84b View commit details
  4. simplified example

    matryer committed Aug 13, 2020
    Copy the full SHA
    b8fa616 View commit details
  5. Copy the full SHA
    098d65e View commit details
  6. Copy the full SHA
    3090053 View commit details
  7. updated docs re metadata

    matryer committed Aug 13, 2020
    Copy the full SHA
    ba5bf28 View commit details
  8. added credit

    matryer committed Aug 13, 2020
    Copy the full SHA
    b1f8d91 View commit details
  9. Copy the full SHA
    1aad254 View commit details
43 changes: 35 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -5,7 +5,14 @@ Go driven rpc code generation tool for right now.
- 100% Go
- Describe services with Go interfaces (with structs, methods, comments, etc.)
- Generate server and client code
- Modify the templates to solve your particular needs
- Production ready templates (or copy and modify)

## Templates

These templates are already being used in production.

* There are some [official Oto templates](https://github.com/pacedotdev/oto/tree/master/otohttp/templates)
* The [Pace CLI tool](https://github.com/pacedotdev/pace/blob/master/oto/cli.go.plush) is generated from an open-source CLI template

## Tutorial

@@ -55,15 +62,15 @@ Use the `oto` tool to generate a client and server:
```bash
mkdir generated
oto -template ./templates/server.go.plush \
-out ./generated/oto.gen.go \
-out ./oto.gen.go \
-ignore Ignorer \
-pkg generated \
./path/to/definition
gofmt -w ./generated/oto.gen.go ./generated/oto.gen.go
./definition
gofmt -w ./oto.gen.go ./oto.gen.go
oto -template ./templates/client.js.plush \
-out ./generated/oto.gen.js \
-out ./oto.gen.js \
-ignore Ignorer \
./path/to/definition
./definition
```

- Run `oto -help` for more information about these flags
@@ -123,14 +130,33 @@ You can provide strings to your templates via the `-params` flag:
```bash
oto \
-template ./templates/server.go.plush \
-out ./generated/oto.gen.go \
-out ./oto.gen.go \
-params "key1:value1,key2:value2" \
./path/to/definition
```

Within your templates, you may access these strings with `<%= params["key1"] %>`.

## Examples
## Comment metadata

It's possible to include additional metadata for services, methods, objects, and fields
in the comments.

```go
// Thing does something.
// field: "value"
type Thing struct {
//...
}
```

The `Metadata["field"]` value will be the string `value`.

* The value must be valid JSON (for strings, use quotes)

Examples are officially supported, but all data is available via the `Metadata` map fields.

### Examples

To provide an example value for a field, you may use the `example:` prefix line
in a comment.
@@ -153,5 +179,6 @@ The example is extracted and made available via the `Field.Example` field.
Special thank you to:

* @mgutz - for struct tag support
* @sethcenterbar - for comment metadata support

![A PACE. project](pace-footer.png)
16 changes: 9 additions & 7 deletions main.go
Original file line number Diff line number Diff line change
@@ -9,6 +9,8 @@ import (
"strings"

"github.com/dustin/go-humanize"
"github.com/pacedotdev/oto/parser"
"github.com/pacedotdev/oto/render"
"github.com/pkg/errors"
)

@@ -48,16 +50,16 @@ flags:`)
flags.PrintDefaults()
return errors.Wrap(err, "params")
}
parser := newParser(flags.Args()...)
p := parser.New(flags.Args()...)
ignoreItems := strings.Split(*ignoreList, ",")
if ignoreItems[0] != "" {
parser.ExcludeInterfaces = ignoreItems
p.ExcludeInterfaces = ignoreItems
}
parser.Verbose = *v
if parser.Verbose {
p.Verbose = *v
if p.Verbose {
fmt.Println("oto - github.com/pacedotdev/oto")
}
def, err := parser.parse()
def, err := p.Parse()
if err != nil {
return err
}
@@ -68,7 +70,7 @@ flags:`)
if err != nil {
return err
}
out, err := render(string(b), def, params)
out, err := render.Render(string(b), def, params)
if err != nil {
return err
}
@@ -84,7 +86,7 @@ flags:`)
if _, err := io.WriteString(w, out); err != nil {
return err
}
if parser.Verbose {
if p.Verbose {
var methodsCount int
for i := range def.Services {
methodsCount += len(def.Services[i].Methods)
3 changes: 3 additions & 0 deletions otohttp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# `otohttp`

Package for rolling Oto services as a JSON/HTTP RPC API.
3 changes: 3 additions & 0 deletions otohttp/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Package otohttp provides JSON/HTTP RPC API support for
// Oto defined services.
package otohttp
124 changes: 124 additions & 0 deletions otohttp/templates/client.go.plush
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Code generated by oto; DO NOT EDIT.

package <%= def.PackageName %>

import (
"bytes"
"compress/gzip"
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"strings"
"time"
"fmt"

"github.com/pkg/errors"
<%= for (importPath, name) in def.Imports { %><%= name %> "<%= importPath %>"
<% } %>
)

// Client is used to access Pace services.
type Client struct {
// RemoteHost is the URL of the remote server that this Client should
// access.
RemoteHost string
// HTTPClient is the http.Client to use when making HTTP requests.
HTTPClient *http.Client
// Debug writes a line of debug log output.
Debug func(s string)
}

// New makes a new Client.
func New(remoteHost string) *Client {
c := &Client{
RemoteHost: remoteHost,
Debug: func(s string) {},
HTTPClient: &http.Client{Timeout:10*time.Second},
}
return c
}

<%= for (service) in def.Services { %>
<%= format_comment_text(service.Comment) %>type <%= service.Name %> struct {
client *Client
}

// New<%= service.Name %> makes a new client for accessing <%= service.Name %> services.
func New<%= service.Name %>(client *Client) *<%= service.Name %> {
return &<%= service.Name %>{
client: client,
}
}

<%= for (method) in service.Methods { %>
<%= format_comment_text(method.Comment) %>func (s *<%= service.Name %>) <%= method.Name %>(ctx context.Context, r <%= method.InputObject.TypeName %>) (*<%= method.OutputObject.TypeName %>, error) {
requestBodyBytes, err := json.Marshal(r)
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>: marshal <%= method.InputObject.TypeName %>")
}
signature, err := generateSignature(requestBodyBytes, s.client.secret)
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>: generate signature <%= method.InputObject.TypeName %>")
}
url := s.client.RemoteHost + "<%= service.Name %>.<%= method.Name %>"
s.client.Debug(fmt.Sprintf("POST %s", url))
s.client.Debug(fmt.Sprintf(">> %s", string(requestBodyBytes)))
req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(requestBodyBytes))
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>: NewRequest")
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept-Encoding", "gzip")
req = req.WithContext(ctx)
resp, err := s.client.HTTPClient.Do(req)
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>")
}
defer resp.Body.Close()
var response struct {
<%= method.OutputObject.TypeName %>
Error string
}
var bodyReader io.Reader = resp.Body
if strings.Contains(resp.Header.Get("Content-Encoding"), "gzip") {
decodedBody, err := gzip.NewReader(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>: new gzip reader")
}
defer decodedBody.Close()
bodyReader = decodedBody
}
respBodyBytes, err := ioutil.ReadAll(bodyReader)
if err != nil {
return nil, errors.Wrap(err, "<%= service.Name %>.<%= method.Name %>: read response body")
}
if err := json.Unmarshal(respBodyBytes, &response); err != nil {
if resp.StatusCode != http.StatusOK {
return nil, errors.Errorf("<%= service.Name %>.<%= method.Name %>: (%d) %v", resp.StatusCode, string(respBodyBytes))
}
return nil, err
}
if response.Error != "" {
return nil, errors.New(response.Error)
}
return &response.<%= method.OutputObject.TypeName %>, nil
}
<% } %>
<% } %>

<%= for (object) in def.Objects { %>
<%= if (!object.Imported) { %>
<%= format_comment_text(object.Comment) %>type <%= object.Name %> struct {
<%= for (field) in object.Fields { %>
<%= if (field.Name != "Error") { %>
<%= format_comment_text(field.Comment) %><%= field.Name %> <%= if (field.Type.Multiple == true) { %>[]<% } %><%= field.Type.TypeName %> `json:"<%= camelize_down(field.Name) %><%= if (field.OmitEmpty) { %>,omitempty<% } %>"`
<% } %>
<% } %>
}
<% } %>
<% } %>
Loading