One model for POST and GET with different "required" field - go

I use go-swagger. I have model like:
// Pet pet
// swagger:model
type Pet struct {
// id
ID int64 `json:"id,omitempty"`
// name
// Required: true
Name *string `json:"name"`
}
and for example in my POST field Name have to be required but for GET not. So how should I add it if I don't want create similar model without required? Because for now my only thought is to create type PetGET struct and type PetPOST struct which, I guess is stupid idea.

If you're generating spec from code, then having a PetGET and PetPOST is not a stupid idea. Usually the program model doesn't match the API model, and you have to repeat definitions just to generate the spec right. So you have a couple of options here:
You can simply mark the field required: false, and deal with it in the GET handler.
If you're generating spec from code, you can create swagger-only models separate from your program models, and for cases like this, create two models with different annotations.

Related

Create something like a 'Parent Struct' to refractor struct defined in my existing Go lang code

I have the below struct used in my existing codebase:
type Token Struct {
// Set of attributes
}
This struct is extensively being used in my existing codebase.
I now have the necessity to maintain two different versions of Token, let's call the other one NewToken. Now, more than 50% of the attributes in NewToken are similar to the existing Token struct.
Being a Java Developer, I'm intrigued to create a parent structure a level above the existing Token struct that will contain the common attributes; let's call it AbstractToken. I could then derive Token and NewToken from AbstractToken and add specific attributes to each of these structs.
I tried the below struct definitions:
type AbstractToken Struct {
// Common token attributes
}
type Token Struct {
abstractToken *AbstractToken
// Attributes specific to Token
}
However, this is breaking my existing code, since I now need to refer the common attributes through the abstractToken attribute. This is simply not an option for me.
Is there a workaround wherein I can pull up the common attributes to reuse within Token & NewToken
in such a way that I don't have to modify my existing codebase?

Custom serialization of specific return type for DataFetcher

I am using Spring for GraphQL (version 2.7.0-M1).
In my domain model, a lot of properties return an object Foo. This object must be serialized to a String based on data available from GraphQlContext. So the schema looks like:
type Parent {
code: String!
foo: String
...
}
It is easy to do this with #SchemaMapping for a specific parent type.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, DataFetchingEnvironment env) {
var context = env.getGraphQlContext();
return ...
However, this is not very DRY. I am looking for a way to have this code at one place, like a custom scalar.
Is there a way to do this with spring-graphql / graphql-java?
Example
An example is a Localized<T> object we use. For instance a Product instance has Localized<String> properties for title and description (and more).
For the GraphQL query we can set the context, part of the context is the Locale. For all Localized property values the value can be converted to the string value for the locale. We are looking for a way to do this automagically. Otherwise it creates a lot of boiler plate code
Would #ContextValue help here? This would remove a bit of boilerplate from your controller handlers.
#SchemaMapping(typeName = "Parent", field = "foo")
public String foo(Parent parent, #ContextValue Foo foo) {
If you'd like something more involved, I think you should elaborate on the exact relationship between an attribute of one or multiple types in your schema, and some random value in the context.
Maybe you could come up with some concrete example here?

One-to-many relation need to define a valid foreign key error

I want to make a webapp and I have a simple data model with a one to many relation. I tried sticking to the documentation of gorm and from my understanding this should work:
package dbModels
import "gorm.io/gorm"
type Post struct {
gorm.Model
Text string
Likes int
Comments []Comment
}
type Comment struct {
gorm.Model
Text string
Likes int
PostID uint
}
I'm migrating these models like that:
db.AutoMigrate(&dbModels.Post{}, &dbModels.Comment{})
Then I want to put this object in post:
func (r *mutationResolver) CreatePost(ctx context.Context, input model.PostInput) (*model.Post, error) {
var items []*model.Comment
post := model.Post{
Text: input.Text,
Likes: 0,
Comments: items,
}
r.DB.Create(&post)
return &post, nil
}
however I get the following error:
2021/01/31 11:23:01 /home/felix/Projekte/GoReact/server/graph/schema.resolvers.go:21 invalid field found for struct github.com/blamefelix/TwitterClone/graph/model.Post's field Comments, need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface
I don't really understand what I'm doing wrong. From the gorm documentation I thought the relation would get managed by gorm if I put it like that? My suspicion is, that I put the wrong data in?
So I've managed to fix it by using the same model for graphql and gorm. The problem must have been that I've pased the wrong data into the db create function

How to require propertyA OR propertyB in a GraphQL Schema

In the type definition below, is there a way to require name or model, instead of name and model?
type Starship {
id: ID!
name: String!
model: String!
length(unit: LengthUnit = METER): Float
}
I may have name or model due to some legacy data limitations. I would rather enforce this at the GraphQL validation layer, rather than in code.
EDIT:
There is some good discussion about adding validation to the graphQL spec, which you can read here: https://github.com/graphql/graphql-js/issues/361
There are also a couple of libraries to extend validation:
https://github.com/xpepermint/graphql-type-factory
https://github.com/stephenhandley/graphql-validated-types
I'm going to stick with validating the types in code, at least until they add better support.
You could try to use union to represent name or model concept . As union only works with object type now , that means you have also model name and model as object type first.
Code wise the schema looks like :
type Name {
value : String!
}
type Model {
value : String!
}
union NameOrModel = Name | Model
type Starship {
id: ID!
nameOrModel : NameOrModel!
length(unit: LengthUnit = METER): Float
}
It is very ugly IMO as it introduces many unnecessary noise and complexity to the schema .So I would prefer to stick with your original schema and do that check manually in the backend.
From the spec:
By default, all types in GraphQL are nullable; the null value is a valid response for all of the above types. To declare a type that disallows null, the GraphQL Non‐Null type can be used. This type wraps an underlying type, and this type acts identically to that wrapped type, with the exception that null is not a valid response for the wrapping type. A trailing exclamation mark is used to denote a field that uses a Non‐Null type like this: name: String!.
An individual field may be nullable or non-nullable. Non-null validation happens at the field level, independent of other fields. So there is no mechanism for validating whether some combination of fields are or are not null.

Trouble defining inter-table relationship

Goal
I am trying to setup a simple has_many association with Gorm: a person has many pets.
Problem
I see the following error when I try to save the Person model.
unsupported type []model.Pet, a slice of struct
Details
Assume I want to save an Person that has many Pets.
type Person struct {
UUID `gorm:"PRIMARY_KEY" json:"uuid"`
Pet []Pet `gorm:"foreignkey:PersonUUID:association_foreignkey:UUID"`
}
type Pet struct {
UUID `gorm:"PRIMARY_KEY" json:"uuid"`
PersonUUID string
}
Then I try to create these two models.
personUUID := "dcf4b3c6-d94c-4b2c-9d66-1cbaedd2cc44"
pets := []Pet{
Pet{
UUID: "..",
PersonUUID: personUUID,
}
}
person := Person{
UUID: personUUID,
Pet: Pet,
}
db.Where("uuid = ?", person.UUID).Update(&person)
Then I get the following error.
sql: converting argument $1 type: unsupported type []model.Pet, a slice of struct
Any idea why this might be happening?
I found out it only happens if you use Update instead of Save.
This is odd, because both should work the same way except that Update will try to save the different fields while Save will replace the current values with the new values.

Resources