Giter Club home page Giter Club logo

oto's People

Contributors

dahernan avatar dylangraham avatar ewanvalentine avatar jhuggart avatar joncalhoun avatar kandros avatar matryer avatar nachtjasmin avatar tcm1911 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oto's Issues

Autogenerated documentation doesn't handle special characters properly

Oto's autogenerated documentation doesn't properly encode special characters such as double quotes. I found this problem while reading pace's docs and reproduced it by myself. You can find an example here:

image

image

Please, feel free to close this issue if this is the intended behavior. I was just trying the tool and noticed it.

Best,
Miguel

Handling Cookies / Status Codes / any other HTTP related headers

How would one drop down to the http.Request or http.Response structs from inside service implementations (as shown below) - for purposes such as accessing r.Header / r.AddCookie() / w.WriteHeader(400) etc?

oto/example/main.go

Lines 17 to 22 in df5a36e

func (greeterService) Greet(ctx context.Context, r GreetRequest) (*GreetResponse, error) {
resp := &GreetResponse{
Greeting: fmt.Sprintf("Hello, %s.", r.Name),
}
return resp, nil
}

/oto/ path shouldn't be hard-coded in otohttp

The oto API base path can be adjusted in principle via the JS template and through the Go-side server setup. However, /oto/ is also hardcoded at one location in otohttp:

s.routes[fmt.Sprintf("/oto/%s.%s", service, method)] = h

If that was made configurable, users would be able to use a different base path (which is currently impossible without forking the project).

Support polymorphic unmarshaling

I want to support polymophic discrimination through serialization. For example, see this short example:

package main

import (
	"encoding/json"
	"fmt"
)

type FruitType string

const (
	AppleType  FruitType = "Apple"
	BananaType FruitType = "Banana"
)

type Fruit interface {
	Type() FruitType
}

type fruitWrapper struct {
	Type FruitType `json:"type"`
}

type Apple struct {
	Type    FruitType `json:"type"`
	Variety string    `json:"variety"`
}

func (Apple) Type() FruitType { return AppleType }

type Banana struct {
	Type   FruitType `json:"type"`
	Length int       `json:"length"`
}

func (Banana) Type() FruitType { return BananaType }

func (f *Fruit) UnmarshalJSON(data []byte) error {
	var wrapper fruitWrapper
	if err := json.Unmarshal(data, &wrapper); err != nil {
		return err
	}

	switch wrapper.Type {
	case AppleType:
		var apple Apple
		if err := json.Unmarshal(data, &apple); err != nil {
			return err
		}
		*f = apple
	case BananaType:
		var banana Banana
		if err := json.Unmarshal(data, &banana); err != nil {
			return err
		}
		*f = banana
	default:
		return fmt.Errorf("unknown type")
	}

	return nil
}

func main() {
	jsonData := []byte(`{"type":"Apple","variety":"Fuji"}`)
	var fruit Fruit
	if err := json.Unmarshal(jsonData, &fruit); err != nil {
		fmt.Println(err)
		return
	}

	switch f := fruit.(type) {
	case Apple:
		fmt.Println("Apple variety:", f.Variety)
	case Banana:
		fmt.Println("Banana length:", f.Length)
	default:
		fmt.Println("Unknown fruit")
	}
}

To support this in oto, I suppose this function needs to support conditional unmarshalling, as above. To get correct TS code generation, we'd need to have all of the defined interfaces/structs tied together somehow, too.

Perhaps in the def, something like this:

type User interface { 
 // specializations: SpecificUser, AltUser, SomeOtherUserType
 Type() UserType
} 
...
// specializationOf: User
type SpecificUser struct {

then some mechanism to emit the correct code. I wonder at what the right level of codegen vs explicit specification is right, especially as Oto has the need to build these up in templates, too.

Error handling server/client ?

First, thanks for this tool! I really like it so far.

I'm wondering a bit though how errors are supposed to be handled? Maybe I'm missing something, but what I'm seeing is this:

If I return a non-nil error from one of the service endpoints, a 500 is returned to the client with the body being the error message (https://github.com/pacedotdev/oto/blob/master/otohttp/templates/server.go.plush#L46-L47). On the client side, the response is assumed to be JSON though (https://github.com/pacedotdev/oto/blob/master/otohttp/templates/client.ts.plush#L38), which leads to a JS error like SyntaxError: Unexpected token c in JSON at position 0. So out-of-the-box that seems a bit broken ... and I'm a bit confused why the "service endpoint error" is not simply handled with s.server.OnErr(w, r, err), like in the other error cases? Would be great if you could shed some light on this!

Small documentation inconsistency

Hi guys.
I was just testing oto and so far so good. I love it. It's simple and does with it suppose to do.

There is a small glitch in understanding on handle mapping that might put the brains of the week of heart in an infinite loop :)

Given the following code

srv := otohttp.NewServer()
RegisterHelloWorld(srv, helloWorldService)
http.Handle("/oto/", srv)

Works, but if I want to do this

srv := otohttp.NewServer()
RegisterHelloWorld(srv, helloWorldService)
http.Handle("/api/v2/", srv)

I get a 404. Took me a solid 30-45 mins until I decided to take a peek inside the lib to see the oto does a base map that defaults to /oto/
The only workaround I found but is ugly and redundant is to match patterns by overwriting the Basepath

srv := otohttp.NewServer()
srv.Basepath = "/api/v1/"

RegisterHelloWorld(srv, helloWorldService)

http.Handle("/api/v1/", srv)

Is there another way to do this?

Is there a way to do matching error on client side ?

I'm trying oto and thanks it's made creating a client lib so easy. I wonder could oto create an error object for the client-side ? I imagine something like this

// definition.go
type ServiceError int

const (
	ErrInternal          ServiceError = 1000
	ErrPermissionDenined ServiceError = 1001
	ErrInvalidArgument   ServiceError = 1002
)

func (s ServiceError) Error() string {
	switch s {
	default: // ErrInternal
		return "internal"
        case ErrInvalidArgument:
                return "invalid_argument" 
	case ErrPermissionDenined:
		return "permission_denied"
	}
}
// client.js
const ErrInvalidArgument = new Error('permission_denied')
// index.js
try {
   res = await greeter.Greets(req)
} catch (err) {
   switch (err.message) {
    case greeter.ErrInvalidArgument:
        // do something
     case greeter.ErrPermissionDenined:
        // do something
     case greeter.ErrInternal:
        // do something
   }
}

Comments are not copied correctly

Given the following input:

type MyResponse struct {
	IsOpen bool `json:"is_open,omitempty"`

	// ClosedReasonCode defines the reason, why a shop can be closed. It is empty, when IsOpen is
	// true. Possible values are: "holiday", "same_day_deadline", "out_of_season".
	// The ClosedReasonMessage provides a user message that can be shown.
	ClosedReasonCode    string `json:"closed_reason_code,omitempty"`
}

the following output is generated:

type MyResponse struct {
	IsOpen bool `json:"is_open,omitempty"`
	// ClosedReasonCode defines the reason, why a shop can be closed. It is empty, when
	// IsOpen is The ClosedReasonMessage provides a user message that can be shown.
	ClosedReasonCode    string `json:"closed_reason_code,omitempty"`
	// Error is string explaining what went wrong. Empty if everything was fine.
	Error string `json:"error,omitempty"`
}

I think this is related to the parsing of the : " in the second comment line.

expected

The comment should be copied as is.

With oto 0.11.0, TypeScript definitions with objects are wrong

With the following API definition and the client.ts.plush template from the otohttp project, we get wrong TypeScript output. This can be reproduced with the current version, v0.11.0, but was not occurring with an older version, in my case v.0.10.14.

package definitions

type SessionService interface {
	UpdateSession(UpdateSessionRequest) UpdateSessionResponse
}

type UpdateSessionRequest struct { Customer *Customer }
type UpdateSessionResponse struct {}
type Customer struct {}

The wrong TypeScript code:

// removed for brevity
export class UpdateSessionRequest {
	constructor(data?: any) {
		if (data) {
			this.customer = new *Customer(data.customer);
		}
	}

	customer?: *Customer;
}
// removed for brevity

Noticing the star before the Customer? That's causing syntax errors.

Source template name available in def

In case there are many source templates, it would be helpful if the generated code pointed to the source template, like:

// Code generated from <%= def.SourceTemplate %>; DO NOT EDIT.

Configurable templating engine

I've been playing around with oto and one of the first things I wondered was why would the templates not be written in the text/template or the html/template?

And with that in mind I was thinking if a feature like a configurable templating engine would be interesting from your point of view.

The benefit is that new comers to oto, who don't know plush (like me), don't have to go and learn a new templating language. There's another, more subjective thing that could be considered: "if the standard lib has what I need, why go to a third party alternative".

The interface for the command line could be a new optional parameter --engine {text/template|html/template[|plush]}. The absence would mean the plush engine and that would preserve compatibility.


I've glanced at plush but at first sight couldn't see the need for it over the std lib (could be an historical thing, like at some point in the past the Go templating engines weren't enough), so if its something obvious I'd love to understand, should you know it.

Copy struct tags to generated server.go

When defining additional struct tags, like the ones from the go-playground/validator package, they aren't copied to the generated oto.gen.go file. I could define them again or do some other type of validation in the implementation, but I think this is a nice and clean way for things like that.

Generate only selected interfaces?

flags:
  -ignore string
        comma separated list of interfaces to ignore

Is it possible to add similar:

flags:
  -include string
        comma separated list of interfaces to generate
  -list
        comma separated list of all defined interfaces  

I would like to have each interface generated in a separate file, so I would call something like:

for interface in `oto -list`; do
  oto -out ./generated/${interface}/${interface}.go -pkg ${interface} -include ${interface}
done

Or is there any other simple method to generate separate files?

Adopting Go generics

In the following article, it mentioned generics. Now the go 1.18 is released and has generics support, I was wondering if there is plan to take advantage of generics?

How code generation wrote our API and CLI.

When generics lands in Go, we will be able to reduce the amount of boilerplate code generated in favour of generic methods. In this world, we may not need to generate much plumbing code at all.

Support URLs as templates

A convenience feature could be to use http urls to reference templates:

mkdir generated
oto -template https://raw.githubusercontent.com/pacedotdev/oto/master/otohttp/templates/server.go.plush \
    -out ./generated/oto.gen.go \
    -ignore Ignorer \
    -pkg generated \
    ./definitions
gofmt -w ./generated/oto.gen.go ./generated/oto.gen.go
oto -template https://raw.githubusercontent.com/pacedotdev/oto/master/otohttp/templates/client.js.plush \
    -out ./generated/oto.gen.js \
    -ignore Ignorer \
    ./definitions
    ```

Running go install

When following the tutorial to install the project:

go install github.com/pacedotdev/oto

# github.com/pacedotdev/oto/parser
pacedotdev/oto/parser/parser.go:161:17: undefined: doc.NewFromFiles

Validation

Is defining a validation schema beyond the scope of oto or is it something that's planned? (thinking something along the lines of swagger)

Multiple Response

It is possible to define:

type GreeterService interface {
  GetGreetings(GetGreetingsRequest) GetGreetingsResponse
}

but some services return list of objects instead of object with a list of object, so:

type GreeterService interface {
  GetGreetings(GetGreetingsRequest) []Greeting
}

but as I understand it is not currently supported. Could this be added?

Byte slice type not handled

The parser doesn't handle byte and []byte types when parsing the JSType. This will cause the generated code to have a type of [] if it is a []byte. According to the JSON encoding documentation, []byte types are base64 encoded to a string. The proper JSType should be a string.

This can be handled in the template by checking if the "go type" is of byte and that it is a multiple. This snippet can handle the case:

<%= for (object) in def.Objects { %>
<%= format_comment_text(object.Comment) %>export interface <%= object.Name %> {
<%= for (field) in object.Fields { %>
        <%= format_comment_text(field.Comment) %>       <%= field.NameLowerCamel %>: <%= if (field.Type.IsObject) { %><%= field.Type.TypeName %><% } else if (field.Type.TypeName == "byte" && field.Type.Multiple) { %>string<% } else { %><%= field.Type.JSType %><% } %><%= if (field.Type.Multiple && field.Type.TypeName != "byte") { %>[]<% } %>;
<% } %>
}
<% } %>

The cleaner way to handle this would be to do it in the parser but I couldn't find a nice way to do it with a major redesign. It would need to the determination between single and multi-type as it's parsing the JSType.

[question] How should errors be handled?

So, oto generates an error property with each response. Should I set this manually, or doing the go way? So, what of these approaches is better:

// this:
	if err != nil {
		return &MyServiceResponse{Error: "not found"}, nil
	}

// or this?
	if err != nil {
		return nil, errors.New("not found")
	}

Unsupported time.Time (json.Marshaler/Unmarshaler?)

Good morning!

Yesterday evening I was giving oto a try and found that time.Time is not supported which made me think it was because I was on Windows at that time.

I just tried on Ubuntu with the same result:
parse input object type: parse type: parse type: /usr/local/go/src/time/time.go:139:2: wall must be exported

Which led me to think oto is not checking if a type satifies json.Marshaler and/or json.Unmarshaler.
Is this something that I should solve in my template?

Here's my sample definition:

package definition

import "time"

type ThingService interface {
	CreateThing(CreateThingRequest) CreateThingResponse
}

type CreateThingRequest struct {
	Thing Thing
}

type CreateThingResponse struct {
	Result bool
}

type Thing struct {
	ID      int64
	OwnerID int64
	Type    string
	Props   map[string]interface{}
	Created time.Time
	Enabled bool
}

I know I could fix this by using a string as type for Created instead but this feels weird as time.Time is supported by encoding/json.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.