Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Design #1

Open
jxsl13 opened this issue Jul 20, 2023 · 7 comments
Open

[DRAFT] Design #1

jxsl13 opened this issue Jul 20, 2023 · 7 comments

Comments

@jxsl13
Copy link
Owner

jxsl13 commented Jul 20, 2023

We want to generate all of the boilerplate code necessary without any external dependencies.

  • we want to utilize the ast standard library contrary to the text/template package.
  • we want to have NO dependency to this generator in the final boilerplate (at most a direct dependency for types such as google/uuid)
  • JSON: every struct type in the OpenAPI spec generates two structs
    • the first being an intermediate struct which contains all values as pointer types (might be generated as anonymous struct in (Un)Marshaler implementations)
    • the second struct is the final user facing struct that contains pointers for optional types and non-pointers for required fields and implements the actual (Un)Marshaler interfaces.
    • the first representation may differ from the second representation in such a way that the first representation may (maybe) only contain primitive types (for example string pointer for a time.Time value) and the second representation the actual time.Time value. We may also consider types that implement encoding.Text(Un)Marshaler as such primitive types that may be used in the first intermediate representation. This would allow us to also represent (if representable by the openapi spec) utime nanos as a potential time.Time because we might be able to parse the uint64/int64 pointer as time.Time.
    • in case that the first representation and the second are identical, and no validation is required, it might make sense to skip the custom implementation of the json.Unmarshaler interface.
  • enum values are to be represented as strings. They need to have a global constant for every allowed value and they also need to be a custom string type that implements the encoding.Text(Un)Marshaler interfaces of which the implementation is generated and also does the validation as well.
    Regular expressions need that validate specific string fields need to be validated by the generator and then generated into global variables that are initialized only once upon application startup with a regexp.MustCompile("...") call.

Example generated code:

type GenObject struct {
	Id uuid.UUID
}

func (g *GenObject) UnmarshalJSON(data []byte) (err error) {
	// intermediate representation
	intermediate := struct {
		Id *string // json primitive types
	}
	err = json.UnmarshalJSON(data, &intermediate)
	if err != nil {
		return err
	}

	// required
	if intermediate.Id == nil {
		return fmt.Errorf("missing required field: id")
	}

	// parse uuid
	uid, err := uuid.Parse(intermediate.id)
	if err != nil {
		return fmt.Errorf("invalid uuid id: %w", err)
	}

	g.Id = uid
}


func (g *GenObject) MarshalJSON() (data []byte, err error) {
	// intermediate representation
	type _intermediate GenObject
	// hide methods (MarshalJSON)
	r := _intermediate(*g)

	// validate response contract
	if r.Id == uuid.NilUUID {
		return nil, errors.New("invalid uuid: id")
	}

	err = json.MarJSON(data, &intermediate)
	if err != nil {
		return err
	}

	return nil
}
@jxsl13
Copy link
Owner Author

jxsl13 commented Jul 21, 2023

@jxsl13
Copy link
Owner Author

jxsl13 commented Jul 21, 2023

@jxsl13
Copy link
Owner Author

jxsl13 commented Aug 1, 2023

@jxsl13
Copy link
Owner Author

jxsl13 commented Aug 16, 2023

@jamietanna
Copy link

FYI I'd recommend https://github.com/pb33f/libopenapi due to its support for OpenAPI 3.1 which kin-openapi doesn't yet support

@jxsl13
Copy link
Owner Author

jxsl13 commented Aug 26, 2023

https://github.com/lucasjones/reggen
interesting library

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants