Cet article est l'article du 14ème jour du Calendrier de l'Avent WACUL 2016. La personne qui écrit travaille chez WACUL depuis septembre de cette année, principalement en écrivant du code go sur le back-end et parfois en python.
Cet article est une continuation de l'article précédent (http://qiita.com/podhmo/items/a12952b07648e42911b4) (l'article précédent est inutilement long donc vous n'avez pas à le forcer à le lire).
La dernière fois, j'ai écrit du code python qui génère du code go à partir d'un exemple de réponse API en imitant JSON-to-Go. .. Cette fois, je voudrais générer du code go en utilisant le résultat de l'analyse du code go.
Par exemple, l'utilisation de go-swagger générera une définition de structure pour la réponse. Il s'agit d'une structure avec une structure similaire, bien qu'elle soit légèrement différente de la structure stockée dans la base de données interne.
Lors de la création de l'API Web réelle, il peut être nécessaire de convertir la structure qui est conservée dans la base de données en structure pour cette réponse. C'est plutôt ennuyeux et fastidieux. Je souhaite générer automatiquement le code de cette partie.
Pour résumer un peu plus l'histoire, ce que je veux, c'est le code de conversion du modèle (src) en objet de réponse (dst). Pour obtenir cela, analysez la définition de structure de la source de conversion et de la destination de conversion et extrayez les informations de type. Dans ce domaine, go est fait avec un package ast etc. Après avoir extrait les informations de type avec l'outil créé, elles sont sorties au format JSON. Il s'agit d'une tentative de générer un code de conversion de src vers dst en utilisant ce JSON.
sample: github api
Je voudrais présenter un exemple d'exécution de la génération de code à l'aide d'un exemple textuel.
À l'origine, c'est une histoire pour générer un processus pour convertir l'expression de la couche de persistance en expression de réponse, mais c'est gênant, donc c'est un peu arbitraire, mais la génération automatique du code du processus de conversion se fait sous la forme suivante. Je voudrais l'essayer.
Je voudrais générer automatiquement le processus de conversion de src en dst, en supposant que le code go des deux structures générées par celles-ci est la structure de l'expression de réponse de model et api pour la persistance, respectivement.
La génération automatique elle-même est créée par la procédure suivante.
convert :: JSON [src], json [dst] => go [convert]
À l'aide de ces deux éléments, le code du processus de conversion de la structure source de conversion (src) vers la structure de destination de conversion (dst) est généré.
Prenons l'exemple de réponse de l'api pour obtenir l'utilisateur authentifié de la partie suivante du document de github. Il n'y a aucune raison particulière de choisir cette API. C'est tout parce que je l'ai remarqué d'une manière ou d'une autre.
Enregistrez-le sous github-get-authenticated-user.json.
{
"login": "octocat",
"id": 1,
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false,
"name": "monalisa octocat",
"company": "GitHub",
"blog": "https://github.com/blog",
"location": "San Francisco",
"email": "[email protected]",
"hireable": false,
"bio": "There once was...",
"public_repos": 2,
"public_gists": 1,
"followers": 20,
"following": 0,
"created_at": "2008-01-14T04:33:35Z",
"updated_at": "2008-01-14T04:33:35Z",
"total_private_repos": 100,
"owned_private_repos": 100,
"private_gists": 81,
"disk_usage": 10000,
"collaborators": 8,
"plan": {
"name": "Medium",
"space": 400,
"private_repos": 20,
"collaborators": 0
}
}
Générez la définition de structure à partir d'ici. Utilisez Script créé dans l'article précédent.
$ swagger_src
mkdir -p src/github
python src/jsontogo/jsontogo.py json/github-get-authenticated-user.json --package github --name AuthenticatedUser | gofmt > src/github/authenticated_user.go
Vous pouvez obtenir la définition de structure suivante. (Enregistrer sous src / github / authenticated_user.go)
package github
import (
"time"
)
/* structure
AuthenticatedUser
Plan
*/
// AuthenticatedUser : auto generated JSON container
type AuthenticatedUser struct {
AvatarURL string `json:"avatar_url" example:"https://github.com/images/error/octocat_happy.gif"`
Bio string `json:"bio" example:"There once was..."`
Blog string `json:"blog" example:"https://github.com/blog"`
Collaborators int `json:"collaborators" example:"8"`
Company string `json:"company" example:"GitHub"`
CreatedAt time.Time `json:"created_at" example:"2008-01-14T04:33:35Z"`
DiskUsage int `json:"disk_usage" example:"10000"`
Email string `json:"email" example:"[email protected]"`
EventsURL string `json:"events_url" example:"https://api.github.com/users/octocat/events{/privacy}"`
Followers int `json:"followers" example:"20"`
FollowersURL string `json:"followers_url" example:"https://api.github.com/users/octocat/followers"`
Following int `json:"following" example:"0"`
FollowingURL string `json:"following_url" example:"https://api.github.com/users/octocat/following{/other_user}"`
GistsURL string `json:"gists_url" example:"https://api.github.com/users/octocat/gists{/gist_id}"`
GravatarID string `json:"gravatar_id" example:""`
HTMLURL string `json:"html_url" example:"https://github.com/octocat"`
Hireable bool `json:"hireable" example:"False"`
ID int `json:"id" example:"1"`
Location string `json:"location" example:"San Francisco"`
Login string `json:"login" example:"octocat"`
Name string `json:"name" example:"monalisa octocat"`
OrganizationsURL string `json:"organizations_url" example:"https://api.github.com/users/octocat/orgs"`
OwnedPrivateRepos int `json:"owned_private_repos" example:"100"`
Plan Plan `json:"plan"`
PrivateGists int `json:"private_gists" example:"81"`
PublicGists int `json:"public_gists" example:"1"`
PublicRepos int `json:"public_repos" example:"2"`
ReceivedEventsURL string `json:"received_events_url" example:"https://api.github.com/users/octocat/received_events"`
ReposURL string `json:"repos_url" example:"https://api.github.com/users/octocat/repos"`
SiteAdmin bool `json:"site_admin" example:"False"`
StarredURL string `json:"starred_url" example:"https://api.github.com/users/octocat/starred{/owner}{/repo}"`
SubscriptionsURL string `json:"subscriptions_url" example:"https://api.github.com/users/octocat/subscriptions"`
TotalPrivateRepos int `json:"total_private_repos" example:"100"`
Type string `json:"type" example:"User"`
URL string `json:"url" example:"https://api.github.com/users/octocat"`
UpdatedAt time.Time `json:"updated_at" example:"2008-01-14T04:33:35Z"`
}
// Plan : auto generated JSON container
type Plan struct {
Collaborators int `json:"collaborators" example:"0"`
Name string `json:"name" example:"Medium"`
PrivateRepos int `json:"private_repos" example:"20"`
Space int `json:"space" example:"400"`
}
Vous avez maintenant la définition de structure pour la source (src).
Ensuite, récupérons la définition de structure pour la destination de conversion (dst). Obtenez la définition de structure go en utilisant go-swagger à partir de la définition swagger.
api.gru
Il existe un service appelé api.gru. Il s'agit d'un service qui partage les spécifications API des services Web. Beaucoup sont fournis au format OpenAPI / Swagger 2.0. Au fait, si vous regardez swagger.yaml que vous pouvez obtenir ici en utilisant ReDoc etc., vous pouvez comprendre à quoi ressemble swagger.
Essayons la génération automatique en utilisant l'API de github comme exemple. Téléchargez le yaml de la définition swagger à partir de l'URL suivante.
$ make swagger_fetch
mkdir -p yaml
wget https://api.apis.guru/v2/specs/github.com/v3/swagger.yaml -O yaml/github-swagger.yaml
gsed -i "s/type: *'null'/type: object/g; s/'+1':/'plus1':/g; s/'-1':/'minus1':/" yaml/github-swagger.yaml
Vous pouvez obtenir yaml comme le lien. Le sed après wget est une correction mineure pour résoudre le problème actuel de go-swagger et le problème enregistré de swagger.yaml.
こちらは普通にgo-swaggerを実行するだけです。以下の様にして実行します。今回はstructの変換だけなのでmodelのみを生成します。本筋とは関係ないのですがなぜか"github.com/go-openapi/swag"
のimportが出力されないという問題があったためgoimportsで追加しています。
$ make swagger_gen
rm -rf dst/swagger/gen
mkdir -p dst/swagger/gen
swagger generate model -f yaml/github-swagger.yaml --target dst/swagger/gen --model-package def
goimports -w dst/swagger/gen/def/*.go
Beaucoup de code est généré, mais cette fois, seul User.go s'en soucie.
package def
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
strfmt "github.com/go-openapi/strfmt"
"github.com/go-openapi/swag"
"github.com/go-openapi/errors"
)
// User user
// swagger:model user
type User struct {
// avatar url
AvatarURL string `json:"avatar_url,omitempty"`
// bio
Bio string `json:"bio,omitempty"`
// blog
Blog string `json:"blog,omitempty"`
// collaborators
Collaborators int64 `json:"collaborators,omitempty"`
// company
Company string `json:"company,omitempty"`
// ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
CreatedAt string `json:"created_at,omitempty"`
// disk usage
DiskUsage int64 `json:"disk_usage,omitempty"`
// email
Email string `json:"email,omitempty"`
// followers
Followers int64 `json:"followers,omitempty"`
// following
Following int64 `json:"following,omitempty"`
// gravatar id
GravatarID string `json:"gravatar_id,omitempty"`
// hireable
Hireable bool `json:"hireable,omitempty"`
// html url
HTMLURL string `json:"html_url,omitempty"`
// id
ID int64 `json:"id,omitempty"`
// location
Location string `json:"location,omitempty"`
// login
Login string `json:"login,omitempty"`
// name
Name string `json:"name,omitempty"`
// owned private repos
OwnedPrivateRepos int64 `json:"owned_private_repos,omitempty"`
// plan
Plan *UserPlan `json:"plan,omitempty"`
// private gists
PrivateGists int64 `json:"private_gists,omitempty"`
// public gists
PublicGists int64 `json:"public_gists,omitempty"`
// public repos
PublicRepos int64 `json:"public_repos,omitempty"`
// total private repos
TotalPrivateRepos int64 `json:"total_private_repos,omitempty"`
// type
Type string `json:"type,omitempty"`
// url
URL string `json:"url,omitempty"`
}
// Validate validates this user
func (m *User) Validate(formats strfmt.Registry) error {
var res []error
if err := m.validatePlan(formats); err != nil {
// prop
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
func (m *User) validatePlan(formats strfmt.Registry) error {
if swag.IsZero(m.Plan) { // not required
return nil
}
if m.Plan != nil {
if err := m.Plan.Validate(formats); err != nil {
return err
}
}
return nil
}
// UserPlan user plan
// swagger:model UserPlan
type UserPlan struct {
// collaborators
Collaborators int64 `json:"collaborators,omitempty"`
// name
Name string `json:"name,omitempty"`
// private repos
PrivateRepos int64 `json:"private_repos,omitempty"`
// space
Space int64 `json:"space,omitempty"`
}
// Validate validates this user plan
func (m *UserPlan) Validate(formats strfmt.Registry) error {
var res []error
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
Au moins, vous devez extraire les informations de type du code go dans la définition de structure. Faisons de notre mieux dans ce domaine. Combien si vous avez un esprit avec ast. J'ai créé une commande appelée go-structjson. Ne vous attendez pas à trop de qualité de code à l'intérieur car c'est un désordre.
À partir du code comme ci-dessous
package alias
// Person :
type Person struct {
Name string
}
type P *Person
type PS []Person
type PS2 []P
type PSP *[]P
Génère le JSON suivant.
{
"module": {
"alias": {
"file": {
"GOPATH/src/github.com/podhmo/go-structjson/examples/alias/person.go": {
"alias": {
"P": {
"candidates": null,
"name": "P",
"original": {
"kind": "pointer",
"value": {
"kind": "primitive",
"value": "Person"
}
}
},
"PS": {
"candidates": null,
"name": "PS",
"original": {
"kind": "array",
"value": {
"kind": "primitive",
"value": "Person"
}
}
},
"PS2": {
"candidates": null,
"name": "PS2",
"original": {
"kind": "array",
"value": {
"kind": "primitive",
"value": "P"
}
}
},
"PSP": {
"candidates": null,
"name": "PSP",
"original": {
"kind": "pointer",
"value": {
"kind": "array",
"value": {
"kind": "primitive",
"value": "P"
}
}
}
}
},
"name": "GOPATH/src/github.com/podhmo/go-structjson/examples/alias/person.go",
"struct": {
"Person": {
"fields": {
"Name": {
"embed": false,
"name": "Name",
"tags": {},
"type": {
"kind": "primitive",
"value": "string"
}
}
},
"name": "Person"
}
}
}
},
"fullname": "github.com/podhmo/go-structjson/examples/alias",
"name": "alias"
}
}
}
Il y avait une histoire que le nom newtype est plus approprié pour ceux gérés par l'alias de nom. Ici, type MyInt int
etc. est appelé alias de type. Pardon.
Un fichier JSON est généré pour chaque src et dst.
$ make swagger_extract
mkdir -p dst/swagger/convert
mkdir -p json/extracted
go-structjson -target src/github > json/extracted/src.json
go-structjson -target dst/swagger/gen/def > json/extracted/dst.json
Eh bien, j'ai pu obtenir le code de la structure de la source de conversion et de la destination de la conversion. Vient ensuite la génération automatique du traitement de conversion. Je crée une bibliothèque appelée goconvert pour cette fois. Le fait qu'il se fasse apparaît à l'endroit où il n'y a qu'à faire est écrit dans le read me. Je vais l'utiliser pour le moment. Code de conversion de src en dst à l'aide de convert.py effectivement créé à l'aide de cette bibliothèque Générer.
$make swagger_convert
mkdir -p dst/swagger/convert
python src/convert.py --logger=DEBUG --src json/extracted/src.json --dst json/extracted/dst.json --override json/extracted/convert.json > dst/swagger/convert/autogen.go || rm dst/swagger/convert/autogen.go
INFO:goconvert.builders:start register function AuthenticatedUserToUser: ['github.com/podhmo/advent2016/src/github.AuthenticatedUser'] -> ['github.com/podhmo/advent2016/dst/swagger/gen/def.User']
DEBUG:goconvert.builders:resolve: avatarurl ('string',) -> avatarurl ('string',)
DEBUG:goconvert.minicode:gencode: ('string',) -> ('string',)
...
NotImplementedError: mapping not found ('time.Time',) -> ('string',)
Oh. Ça ne marche pas.
Je n'arrive pas à générer le code pour string
from time.Time
. En regardant à l'intérieur, il me semblait que j'avais du mal à gérer Created At.
src (généré à partir de la réponse de l'API)
type AuthenticatedUser struct {
AvatarURL string `json:"avatar_url" example:"https://github.com/images/error/octocat_happy.gif"`
...
CreatedAt time.Time `json:"created_at" example:"2008-01-14T04:33:35Z"`
dst (généré à partir de swagger.yaml)
// User user
// swagger:model user
type User struct {
// avatar url
AvatarURL string `json:"avatar_url,omitempty"`
...
// ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ
CreatedAt string `json:"created_at,omitempty"`
Eh bien, c'est en un sens naturel et inévitable. Peu importe combien vous tracez les informations de type go, vous ne savez pas comment convertir time.Time en chaîne. Seul le développeur le sait. Écrivez le processus de conversion time.Time en chaîne comme primitive.go dans le même package que la destination de sortie du processus de conversion.
package convert
import "time"
// TimeToString :
func TimeToString(t time.Time) string {
return t.Format(time.RFC3339)
}
Puis refaites la sortie JSON. Cette fois, go-funcjson est également ajouté (en passant le JSON généré par go-funcjson, la fonction de traitement de conversion manuscrite sera utilisée telle quelle au moment de la génération automatique).
$ make swagger_extract
mkdir -p dst/swagger/convert
mkdir -p json/extracted
go-structjson -target src/github > json/extracted/src.json
go-structjson -target dst/swagger/gen/def > json/extracted/dst.json
go-funcjson -target dst/swagger/convert > json/extracted/convert.json || echo '{}' > json/extracted/convert.json
...
-- write: convert --
gofmt -w dst/swagger/convert/autogen.go
Cette fois, l'opération a réussi. Le code suivant est généré (dst / swagger / convert / autogen.go).
package convert
import (
def "github.com/podhmo/advent2016/dst/swagger/gen/def"
github "github.com/podhmo/advent2016/src/github"
)
// AuthenticatedUserToUser :
func AuthenticatedUserToUser(from *github.AuthenticatedUser) *def.User {
to := &def.User{}
to.AvatarURL = from.AvatarURL
to.Bio = from.Bio
to.Blog = from.Blog
tmp1 := (int64)(from.Collaborators)
to.Collaborators = tmp1
to.Company = from.Company
to.CreatedAt = TimeToString(from.CreatedAt)
tmp2 := (int64)(from.DiskUsage)
to.DiskUsage = tmp2
to.Email = from.Email
tmp3 := (int64)(from.Followers)
to.Followers = tmp3
tmp4 := (int64)(from.Following)
to.Following = tmp4
to.GravatarID = from.GravatarID
to.Hireable = from.Hireable
to.HTMLURL = from.HTMLURL
tmp5 := (int64)(from.ID)
to.ID = tmp5
to.Location = from.Location
to.Login = from.Login
to.Name = from.Name
tmp6 := (int64)(from.OwnedPrivateRepos)
to.OwnedPrivateRepos = tmp6
to.Plan = PlanToUserPlan(&(from.Plan))
tmp7 := (int64)(from.PrivateGists)
to.PrivateGists = tmp7
tmp8 := (int64)(from.PublicGists)
to.PublicGists = tmp8
tmp9 := (int64)(from.PublicRepos)
to.PublicRepos = tmp9
tmp10 := (int64)(from.TotalPrivateRepos)
to.TotalPrivateRepos = tmp10
to.Type = from.Type
to.URL = from.URL
return to
}
// PlanToUserPlan :
func PlanToUserPlan(from *github.Plan) *def.UserPlan {
to := &def.UserPlan{}
tmp11 := (int64)(from.Collaborators)
to.Collaborators = tmp11
to.Name = from.Name
tmp12 := (int64)(from.PrivateRepos)
to.PrivateRepos = tmp12
tmp13 := (int64)(from.Space)
to.Space = tmp13
return to
}
Le TimeToString ()
ajouté dans primitive.go est également utilisé dans la partie CreatedAt
. Va-t-il compiler?
$ (cd dst/swagger/convert/; go install)
Ça a l'air bien.
Utilisons en fait le code de traitement de conversion généré. Exécutez le code suivant.
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"github.com/davecgh/go-spew/spew"
"github.com/podhmo/advent2016/dst/swagger/convert"
"github.com/podhmo/advent2016/src/github"
)
func main() {
decoder := json.NewDecoder(os.Stdin)
var from github.AuthenticatedUser
if err := decoder.Decode(&from); err != nil {
log.Fatal(err)
}
{
fmt.Println("------------------------------")
fmt.Println("source:")
fmt.Println("------------------------------")
spew.Dump(from)
}
{
to := convert.AuthenticatedUserToUser(&from)
fmt.Println("------------------------------")
fmt.Println("destination:")
fmt.Println("------------------------------")
spew.Dump(to)
}
}
Si le code de traitement de conversion est généré avec succès, la compilation réussira. Vous devriez pouvoir le faire. Comme c'est gênant, passons la réponse de l'API github téléchargée à l'origine à l'entrée.
$ make swagger_run1
cat json/github-get-authenticated-user.json | go run dst/swagger/main/spew/*.go
------------------------------
source:
------------------------------
(github.AuthenticatedUser) {
AvatarURL: (string) (len=49) "https://github.com/images/error/octocat_happy.gif",
Bio: (string) (len=17) "There once was...",
Blog: (string) (len=23) "https://github.com/blog",
Collaborators: (int) 8,
Company: (string) (len=6) "GitHub",
CreatedAt: (time.Time) 2008-01-14 04:33:35 +0000 UTC,
DiskUsage: (int) 10000,
Email: (string) (len=18) "[email protected]",
EventsURL: (string) (len=53) "https://api.github.com/users/octocat/events{/privacy}",
Followers: (int) 20,
FollowersURL: (string) (len=46) "https://api.github.com/users/octocat/followers",
Following: (int) 0,
FollowingURL: (string) (len=59) "https://api.github.com/users/octocat/following{/other_user}",
GistsURL: (string) (len=52) "https://api.github.com/users/octocat/gists{/gist_id}",
GravatarID: (string) "",
HTMLURL: (string) (len=26) "https://github.com/octocat",
Hireable: (bool) false,
ID: (int) 1,
Location: (string) (len=13) "San Francisco",
Login: (string) (len=7) "octocat",
Name: (string) (len=16) "monalisa octocat",
OrganizationsURL: (string) (len=41) "https://api.github.com/users/octocat/orgs",
OwnedPrivateRepos: (int) 100,
Plan: (github.Plan) {
Collaborators: (int) 0,
Name: (string) (len=6) "Medium",
PrivateRepos: (int) 20,
Space: (int) 400
},
PrivateGists: (int) 81,
PublicGists: (int) 1,
PublicRepos: (int) 2,
ReceivedEventsURL: (string) (len=52) "https://api.github.com/users/octocat/received_events",
ReposURL: (string) (len=42) "https://api.github.com/users/octocat/repos",
SiteAdmin: (bool) false,
StarredURL: (string) (len=59) "https://api.github.com/users/octocat/starred{/owner}{/repo}",
SubscriptionsURL: (string) (len=50) "https://api.github.com/users/octocat/subscriptions",
TotalPrivateRepos: (int) 100,
Type: (string) (len=4) "User",
URL: (string) (len=36) "https://api.github.com/users/octocat",
UpdatedAt: (time.Time) 2008-01-14 04:33:35 +0000 UTC
}
------------------------------
destination:
------------------------------
(*def.User)(0xc4200ae140)({
AvatarURL: (string) (len=49) "https://github.com/images/error/octocat_happy.gif",
Bio: (string) (len=17) "There once was...",
Blog: (string) (len=23) "https://github.com/blog",
Collaborators: (int64) 8,
Company: (string) (len=6) "GitHub",
CreatedAt: (string) (len=20) "2008-01-14T04:33:35Z",
DiskUsage: (int64) 10000,
Email: (string) (len=18) "[email protected]",
Followers: (int64) 20,
Following: (int64) 0,
GravatarID: (string) "",
Hireable: (bool) false,
HTMLURL: (string) (len=26) "https://github.com/octocat",
ID: (int64) 1,
Location: (string) (len=13) "San Francisco",
Login: (string) (len=7) "octocat",
Name: (string) (len=16) "monalisa octocat",
OwnedPrivateRepos: (int64) 100,
Plan: (*def.UserPlan)(0xc4204da1b0)({
Collaborators: (int64) 0,
Name: (string) (len=6) "Medium",
PrivateRepos: (int64) 20,
Space: (int64) 400
}),
PrivateGists: (int64) 81,
PublicGists: (int64) 1,
PublicRepos: (int64) 2,
TotalPrivateRepos: (int64) 100,
Type: (string) (len=4) "User",
URL: (string) (len=36) "https://api.github.com/users/octocat"
})
Cela semble fonctionner. (Au fait, si la structure est exactement la même, il peut être plus facile de convertir la valeur via JSON avec json.Unmarshal
après json.Marshal
)
Le Makefile pour les commandes utilisées pour la conversion est ici.
En fait, le src du code utilisé dans la conversion de code jusqu'à présent est le même que celui de l'article précédent, mais ce n'est pas complètement le même. Dernier code Je commentais la partie suivante.
# elif "://" in val:
# return "github.com/go-openapi/strfmt.Uri"
Décommentez ceci et essayez de le générer à nouveau.
$ make swagger_src
...
$ make swagger_extract
...
$ make swagger_convert
...
KeyError: 'Uri'
J'ai échoué. En fait, c'est parce que la bibliothèque github.com/go-openapi/strfmt que j'utilise depuis que j'ai écrit l'article précédent a été mise à jour. fait. Plus précisément, il semble que «strfmt.Uri» soit devenu «strfmt.URI».
Mettons-le à jour à nouveau et générons-le à nouveau.
$ go get -u github.com/go-openapi/strfmt
$ gsed -i 's/strfmt.Uri/strfmt.URI/' src/jsontogo/jsontogo.py
$ make swagger_src
$ make swagger_extract
$ make swagger_convert
Cette fois, il semble avoir réussi. Bien sûr, vous pouvez également effectuer des conversions.
$ make swagger_run1
cat json/github-get-authenticated-user.json | go run dst/swagger/main/spew/*.go
------------------------------
source:
------------------------------
(github.AuthenticatedUser) {
AvatarURL: (strfmt.URI) (len=49) https://github.com/images/error/octocat_happy.gif,
Bio: (string) (len=17) "There once was...",
Blog: (strfmt.URI) (len=23) https://github.com/blog,
Collaborators: (int) 8,
Company: (string) (len=6) "GitHub",
CreatedAt: (time.Time) 2008-01-14 04:33:35 +0000 UTC,
DiskUsage: (int) 10000,
Email: (string) (len=18) "[email protected]",
EventsURL: (strfmt.URI) (len=53) https://api.github.com/users/octocat/events{/privacy},
Followers: (int) 20,
FollowersURL: (strfmt.URI) (len=46) https://api.github.com/users/octocat/followers,
Following: (int) 0,
FollowingURL: (strfmt.URI) (len=59) https://api.github.com/users/octocat/following{/other_user},
GistsURL: (strfmt.URI) (len=52) https://api.github.com/users/octocat/gists{/gist_id},
GravatarID: (string) "",
HTMLURL: (strfmt.URI) (len=26) https://github.com/octocat,
Hireable: (bool) false,
ID: (int) 1,
Location: (string) (len=13) "San Francisco",
Login: (string) (len=7) "octocat",
Name: (string) (len=16) "monalisa octocat",
OrganizationsURL: (strfmt.URI) (len=41) https://api.github.com/users/octocat/orgs,
OwnedPrivateRepos: (int) 100,
Plan: (github.Plan) {
Collaborators: (int) 0,
Name: (string) (len=6) "Medium",
PrivateRepos: (int) 20,
Space: (int) 400
},
PrivateGists: (int) 81,
PublicGists: (int) 1,
PublicRepos: (int) 2,
ReceivedEventsURL: (strfmt.URI) (len=52) https://api.github.com/users/octocat/received_events,
ReposURL: (strfmt.URI) (len=42) https://api.github.com/users/octocat/repos,
SiteAdmin: (bool) false,
StarredURL: (strfmt.URI) (len=59) https://api.github.com/users/octocat/starred{/owner}{/repo},
SubscriptionsURL: (strfmt.URI) (len=50) https://api.github.com/users/octocat/subscriptions,
TotalPrivateRepos: (int) 100,
Type: (string) (len=4) "User",
URL: (strfmt.URI) (len=36) https://api.github.com/users/octocat,
UpdatedAt: (time.Time) 2008-01-14 04:33:35 +0000 UTC
}
------------------------------
destination:
------------------------------
(*def.User)(0xc42015e280)({
AvatarURL: (string) (len=49) "https://github.com/images/error/octocat_happy.gif",
Bio: (string) (len=17) "There once was...",
Blog: (string) (len=23) "https://github.com/blog",
Collaborators: (int64) 8,
Company: (string) (len=6) "GitHub",
CreatedAt: (string) (len=20) "2008-01-14T04:33:35Z",
DiskUsage: (int64) 10000,
Email: (string) (len=18) "[email protected]",
Followers: (int64) 20,
Following: (int64) 0,
GravatarID: (string) "",
Hireable: (bool) false,
HTMLURL: (string) (len=26) "https://github.com/octocat",
ID: (int64) 1,
Location: (string) (len=13) "San Francisco",
Login: (string) (len=7) "octocat",
Name: (string) (len=16) "monalisa octocat",
OwnedPrivateRepos: (int64) 100,
Plan: (*def.UserPlan)(0xc420330420)({
Collaborators: (int64) 0,
Name: (string) (len=6) "Medium",
PrivateRepos: (int64) 20,
Space: (int64) 400
}),
PrivateGists: (int64) 81,
PublicGists: (int64) 1,
PublicRepos: (int64) 2,
TotalPrivateRepos: (int64) 100,
Type: (string) (len=4) "User",
URL: (string) (len=36) "https://api.github.com/users/octocat"
})
Cette fois, j'ai analysé le code de go et généré le code de conversion d'une structure à une autre. Au fait, c'était gênant, alors j'ai arrêté d'écrire des histoires internes détaillées. J'ai utilisé python pour la génération de code, mais il peut être plus beau et plus pratique à compléter avec go. Il y a quelques sujets dont je peux parler, comme la partie analyse du pointeur, la gestion des alias (nouveau type), le code correspondant aux tranches, que faire si la correspondance de conversion n'est pas trouvée, donc je peux l'écrire si j'en ai envie Peut être.
J'ajouterai un bonus car le code généré n'a pas d'élan. J'essaierai d'être méchant, comme jouer avec certaines définitions de type de src pour en faire un pointeur.
diff --git a/src/github/authenticated_user.go b/src/github/authenticated_user.go
index 8893144..7e04142 100644
--- a/src/github/authenticated_user.go
+++ b/src/github/authenticated_user.go
@@ -11,8 +11,8 @@ AuthenticatedUser
*/
// AuthenticatedUser : auto generated JSON container
type AuthenticatedUser struct {
- AvatarURL strfmt.URI `json:"avatar_url" example:"https://github.com/images/error/octocat_happy.gif"`
- Bio string `json:"bio" example:"There once was..."`
+ AvatarURL *******strfmt.URI `json:"avatar_url" example:"https://github.com/images/error/octocat_happy.gif"`
+ Bio *********string `json:"bio" example:"There once was..."`
Blog strfmt.URI `json:"blog" example:"https://github.com/blog"`
Collaborators int `json:"collaborators" example:"8"`
Company string `json:"company" example:"GitHub"`
@@ -35,10 +35,10 @@ type AuthenticatedUser struct {
OrganizationsURL strfmt.URI `json:"organizations_url" example:"https://api.github.com/users/octocat/orgs"`
OwnedPrivateRepos int `json:"owned_private_repos" example:"100"`
Plan Plan `json:"plan"`
- PrivateGists int `json:"private_gists" example:"81"`
- PublicGists int `json:"public_gists" example:"1"`
- PublicRepos int `json:"public_repos" example:"2"`
- ReceivedEventsURL strfmt.URI `json:"received_events_url" example:"https://api.github.com/users/octocat/received_events"`
+ PrivateGists *int `json:"private_gists" example:"81"`
+ PublicGists **int `json:"public_gists" example:"1"`
+ PublicRepos ***int `json:"public_repos" example:"2"`
+ ReceivedEventsURL ****strfmt.URI `json:"received_events_url" example:"https://api.github.com/users/octocat/received_events"`
ReposURL strfmt.URI `json:"repos_url" example:"https://api.github.com/users/octocat/repos"`
SiteAdmin bool `json:"site_admin" example:"False"`
StarredURL strfmt.URI `json:"starred_url" example:"https://api.github.com/users/octocat/starred{/owner}{/repo}"`
Le code généré ressemble à ceci: Cela semble fonctionner correctement. À bien y penser, il n'y avait pas de tranches dans cet exemple.
package convert
import (
def "github.com/podhmo/advent2016/dst/swagger/gen/def"
github "github.com/podhmo/advent2016/src/github"
)
// AuthenticatedUserToUser :
func AuthenticatedUserToUser(from *github.AuthenticatedUser) *def.User {
to := &def.User{}
if from.AvatarURL != nil {
tmp1 := *(from.AvatarURL)
if tmp1 != nil {
tmp2 := *(tmp1)
if tmp2 != nil {
tmp3 := *(tmp2)
if tmp3 != nil {
tmp4 := *(tmp3)
if tmp4 != nil {
tmp5 := *(tmp4)
if tmp5 != nil {
tmp6 := *(tmp5)
if tmp6 != nil {
tmp7 := *(tmp6)
tmp8 := (string)(tmp7)
to.AvatarURL = tmp8
}
}
}
}
}
}
}
if from.Bio != nil {
tmp9 := *(from.Bio)
if tmp9 != nil {
tmp10 := *(tmp9)
if tmp10 != nil {
tmp11 := *(tmp10)
if tmp11 != nil {
tmp12 := *(tmp11)
if tmp12 != nil {
tmp13 := *(tmp12)
if tmp13 != nil {
tmp14 := *(tmp13)
if tmp14 != nil {
tmp15 := *(tmp14)
if tmp15 != nil {
tmp16 := *(tmp15)
if tmp16 != nil {
tmp17 := *(tmp16)
to.Bio = tmp17
}
}
}
}
}
}
}
}
}
tmp18 := (string)(from.Blog)
to.Blog = tmp18
tmp19 := (int64)(from.Collaborators)
to.Collaborators = tmp19
to.Company = from.Company
to.CreatedAt = TimeToString(from.CreatedAt)
tmp20 := (int64)(from.DiskUsage)
to.DiskUsage = tmp20
to.Email = from.Email
tmp21 := (int64)(from.Followers)
to.Followers = tmp21
tmp22 := (int64)(from.Following)
to.Following = tmp22
to.GravatarID = from.GravatarID
to.Hireable = from.Hireable
tmp23 := (string)(from.HTMLURL)
to.HTMLURL = tmp23
tmp24 := (int64)(from.ID)
to.ID = tmp24
to.Location = from.Location
to.Login = from.Login
to.Name = from.Name
tmp25 := (int64)(from.OwnedPrivateRepos)
to.OwnedPrivateRepos = tmp25
to.Plan = PlanToUserPlan(&(from.Plan))
if from.PrivateGists != nil {
tmp26 := *(from.PrivateGists)
tmp27 := (int64)(tmp26)
to.PrivateGists = tmp27
}
if from.PublicGists != nil {
tmp28 := *(from.PublicGists)
if tmp28 != nil {
tmp29 := *(tmp28)
tmp30 := (int64)(tmp29)
to.PublicGists = tmp30
}
}
if from.PublicRepos != nil {
tmp31 := *(from.PublicRepos)
if tmp31 != nil {
tmp32 := *(tmp31)
if tmp32 != nil {
tmp33 := *(tmp32)
tmp34 := (int64)(tmp33)
to.PublicRepos = tmp34
}
}
}
tmp35 := (int64)(from.TotalPrivateRepos)
to.TotalPrivateRepos = tmp35
to.Type = from.Type
tmp36 := (string)(from.URL)
to.URL = tmp36
return to
}
// PlanToUserPlan :
func PlanToUserPlan(from *github.Plan) *def.UserPlan {
to := &def.UserPlan{}
tmp37 := (int64)(from.Collaborators)
to.Collaborators = tmp37
to.Name = from.Name
tmp38 := (int64)(from.PrivateRepos)
to.PrivateRepos = tmp38
tmp39 := (int64)(from.Space)
to.Space = tmp39
return to
}
<! - ## Ramasser les feuilles mortes !-- !-- misc !-- ! ---- Que faire si je veux écrire à la main une partie de la fonction de conversion? ! ---- Qu'est-ce que la prise en charge du pointeur? ! ---- Quel est le support de l'interface? ! --- Quelle est la correspondance des tranches? ! ---- Quelle est la correspondance du type alias (nouveau type)? ! ---- Qu'est-ce que le support intégré? ! ---- Quelle est la correspondance des champs non convertibles? ! --- Prend en charge les fluctuations de notation (Id, ID, ...) ! --- Prend-il en charge plusieurs fonctions d'argument? ! --- Que se passe-t-il si une nouvelle fonction manuscrite nécessite un argument supplémentaire? ! ---- Est-ce que cela fonctionne si vous souhaitez utiliser une fonction que vous avez définie au milieu de l'omission de la distribution? ->
Recommended Posts