Dieser Artikel ist der 14. Tagesartikel von WACUL Adventskalender 2016. Die Person, die schreibt, arbeitet seit September dieses Jahres bei WACUL. Sie schreibt hauptsächlich Go-Code im Backend und manchmal Python.
Dieser Artikel ist eine Fortsetzung des vorherigen Artikels (http://qiita.com/podhmo/items/a12952b07648e42911b4) (der vorherige Artikel ist nutzlos lang, sodass Sie ihn nicht zum Lesen zwingen müssen).
Letztes Mal habe ich Python-Code geschrieben, der aus dem API-Antwortbeispiel Go-Code generiert, indem er JSON-to-Go imitiert. .. Dieses Mal möchte ich Go-Code anhand des Ergebnisses der Analyse von Go-Code generieren.
Wenn Sie beispielsweise go-swagger verwenden, wird eine Strukturdefinition für die Antwort generiert. Dies ist eine Struktur mit einer ähnlichen Struktur, die sich jedoch geringfügig von der in der internen Datenbank gespeicherten Struktur unterscheidet.
Beim Erstellen der eigentlichen Web-API muss möglicherweise die in der Datenbank persistierte Struktur für diese Antwort in die Struktur konvertiert werden. Das ist ziemlich langweilig und langweilig. Ich möchte den Code für diesen Teil automatisch generieren.
Um die Geschichte ein wenig zusammenzufassen, möchte ich den Konvertierungscode vom Modell (src) zum Antwortobjekt (dst). Um dies zu erhalten, analysieren Sie die Strukturdefinition der Konvertierungsquelle und des Konvertierungsziels und extrahieren Sie die Typinformationen. In diesem Bereich wird go mit einem Paket usw. hergestellt. Nach dem Extrahieren der Typinformationen mit dem erstellten Tool werden diese als JSON ausgegeben. Es ist ein Versuch, mit diesem JSON einen Konvertierungscode von src nach dst zu generieren.
sample: github api
Ich möchte ein Beispiel für die Ausführung der Codegenerierung anhand eines Textbeispiels vorstellen.
Ursprünglich ist es eine Geschichte, einen Prozess zum Konvertieren des Ausdrucks der Persistenzschicht in den Ausdruck der Antwort zu generieren. Da dies jedoch problematisch ist, ist es ein wenig willkürlich, aber der Code des Konvertierungsprozesses wird automatisch in der folgenden Form generiert. Ich würde es gerne probieren.
Ich möchte den Prozess der Konvertierung von src nach dst automatisch generieren, vorausgesetzt, der go-Code der beiden von diesen generierten Strukturen ist die Struktur des Antwortausdrucks von model bzw. api für die Persistenz.
Die automatische Generierung selbst wird wie folgt erstellt.
extract :: go [src] => JSON [src]
extract :: go [dst] => JSON [dst]
convert :: JSON [src], json [dst] => go [convert]
Mit diesen beiden wird der Code des Konvertierungsprozesses von der Struktur der Konvertierungsquelle (src) zur Struktur des Konvertierungsziels (dst) generiert.
Nehmen Sie das Antwortbeispiel von api, um den authentifizierten Benutzer aus dem folgenden Teil des Github-Dokuments abzurufen. Es gibt keinen besonderen Grund, diese API zu wählen. Das ist alles, weil ich es irgendwie bemerkt habe.
Speichern Sie es als 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
}
}
Generieren Sie hier die Strukturdefinition. Verwenden Sie im vorherigen Artikel erstelltes Skript.
$ 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
Sie können die folgende Strukturdefinition erhalten. (Speichern als 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"`
}
Jetzt haben Sie die Strukturdefinition für die Quelle (src).
Als nächstes erhalten wir die Strukturdefinition für das Konvertierungsziel (dst). Rufen Sie die Go-Strukturdefinition mit go-swagger aus der Swagger-Definition ab.
api.gru
Es gibt einen Dienst namens api.gru. Dies ist ein Dienst, der die API-Spezifikationen von Webdiensten gemeinsam nutzt. Viele werden im OpenAPI / Swagger 2.0-Format bereitgestellt. Übrigens, wenn Sie sich swagger.yaml ansehen, das Sie mit ReDoc usw. hier abrufen können, können Sie verstehen, wie swagger ist.
Versuchen wir die automatische Generierung am Beispiel der API von github. Laden Sie yaml of swagger definition von der folgenden URL herunter.
$ 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
Sie können [yaml like the link] erhalten (https://github.com/podhmo/advent2016/blob/master/yaml/github-swagger.yaml). Das sed after wget ist eine kleine Korrektur, um das aktuelle Problem mit go-swagger und das registrierte Problem mit swagger.yaml zu beheben.
こちらは普通に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
Es wird viel Code generiert, aber diesmal kümmert sich nur User.go darum.
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
}
Zumindest müssen Sie die Typinformationen aus dem Go-Code in der Strukturdefinition extrahieren. Lassen Sie uns in diesem Bereich unser Bestes geben. Wie viel, wenn Sie einen Geist mit Ast haben. Ich habe einen Befehl namens go-structjson erstellt. Erwarten Sie nicht zu viel Codequalität im Inneren, da dies ein Chaos ist.
Aus dem Code wie unten
package alias
// Person :
type Person struct {
Name string
}
type P *Person
type PS []Person
type PS2 []P
type PSP *[]P
Gibt den folgenden JSON aus.
{
"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"
}
}
}
Es gab eine Geschichte, dass der Name newtype besser für diejenigen geeignet ist, die vom Namensalias behandelt werden. Hier wird "Typ MyInt int" usw. als Typalias bezeichnet. Es tut uns leid.
Für jeden src und dst wird eine JSON-Datei ausgegeben.
$ 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
Nun, ich konnte den Code der Struktur der Konvertierungsquelle und des Konvertierungsziels abrufen. Als nächstes folgt die automatische Generierung der Konvertierungsverarbeitung. Ich mache gerade eine Bibliothek namens goconvert für diese Zeit. Die Tatsache, dass es gemacht wird, erscheint an der Stelle, an der nur zu tun ist, steht im Read me. Ich werde dies vorerst nutzen. Code zum Konvertieren von src in dst mit convert.py, der tatsächlich mit dieser Bibliothek erstellt wurde Generieren.
$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. Es funktioniert nicht.
Ich kann den Code für string
scheinbar nicht aus time.Time
generieren. Als ich hineinschaute, schien es, als hätte ich Probleme beim Umgang mit Created At.
src (generiert aus der API-Antwort)
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 (generiert aus 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"`
Nun, das ist in gewissem Sinne natürlich und unvermeidlich. Unabhängig davon, wie viel Sie den Go-Typ-Informationen nachverfolgen, wissen Sie nicht, wie Sie time.Time in string konvertieren können. Nur der Entwickler weiß es. Schreiben Sie die folgende Zeit. Zeit-zu-Zeichenfolge-Konvertierungsprozess als primitive.go in dasselbe Paket wie das Ausgabeziel des Konvertierungsprozesses.
package convert
import "time"
// TimeToString :
func TimeToString(t time.Time) string {
return t.Format(time.RFC3339)
}
Wiederholen Sie dann die JSON-Ausgabe. Dieses Mal wird auch go-funcjson hinzugefügt (durch Übergeben des von go-funcjson generierten JSON wird die handschriftliche Konvertierungsverarbeitungsfunktion wie zum Zeitpunkt der automatischen Generierung verwendet).
$ 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
Diesmal war es erfolgreich. Der folgende Code wird generiert (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
}
Das in primitive.go hinzugefügte "TimeToString ()" wird auch im Teil "CreatedAt" verwendet. Wird es kompiliert?
$ (cd dst/swagger/convert/; go install)
Es sieht okay aus.
Verwenden wir tatsächlich den generierten Konvertierungsverarbeitungscode. Führen Sie den folgenden Code aus.
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)
}
}
Wenn der Konvertierungsverarbeitungscode erfolgreich generiert wurde, wird die Kompilierung bestanden. Sie sollten dazu in der Lage sein. Da dies problematisch ist, übergeben wir die Antwort der ursprünglich heruntergeladenen Github-API an die Eingabe.
$ 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"
})
Es scheint zu funktionieren. (Übrigens, wenn die Struktur genau gleich ist, ist es möglicherweise einfacher, den Wert über JSON mit json.Unmarshal
nach json.Marshal
zu konvertieren.)
Das Makefile für die für die Konvertierung verwendeten Befehle lautet hier.
Tatsächlich ist der Quellcode des Codes, der bisher bei der Codekonvertierung verwendet wurde, derselbe wie im vorherigen Artikel, aber nicht vollständig derselbe. Letzter Code Ich habe den folgenden Teil auskommentiert.
# elif "://" in val:
# return "github.com/go-openapi/strfmt.Uri"
Kommentieren Sie dies aus und versuchen Sie es erneut zu generieren.
$ make swagger_src
...
$ make swagger_extract
...
$ make swagger_convert
...
KeyError: 'Uri'
Ich habe versagt. Dies liegt daran, dass die Bibliothek github.com/go-openapi/strfmt, die ich seit dem Schreiben des vorherigen Artikels verwende, aktualisiert wurde. tat. Insbesondere scheint sich "strfmt.Uri" in "strfmt.URI" geändert zu haben.
Lassen Sie es uns erneut aktualisieren und dann erneut generieren.
$ 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
Diesmal scheint es gelungen zu sein. Natürlich können Sie auch Konvertierungen durchführen.
$ 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"
})
Dieses Mal habe ich den Code of go analysiert und den Code für die Konvertierung von einer Struktur in eine andere generiert. Übrigens war es mühsam, also hörte ich auf, detaillierte interne Geschichten zu schreiben. Ich habe Python für die Codegenerierung verwendet, aber es kann schöner und bequemer sein, mit go abzuschließen. Es gibt einige Themen, über die ich sprechen kann, wenn ich die Energie habe, über den Analyseteil des Zeigers, die Behandlung von Alias (neuer Typ), den Code, der Slices entspricht, zu sprechen, was zu tun ist, wenn die Korrespondenz der Konvertierung nicht gefunden wird, also kann ich sie schreiben, wenn ich Lust dazu habe Vielleicht.
Ich werde einen Bonus hinzufügen, da der generierte Code keine Dynamik hat. Ich werde versuchen, es zu einem Zeiger zu machen, indem ich mit einigen Typdefinitionen von src spiele.
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}"`
Der generierte Code sieht folgendermaßen aus: Es scheint richtig zu funktionieren. Wenn Sie sich das vorstellen, gab es in diesem Beispiel keine Scheiben.
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
}
<! - ## Aufgefallene Blätter aufheben !-- !-- misc !-- ! ---- Was ist, wenn ich einen Teil der Konvertierungsfunktion handschriftlich schreiben möchte? ! ---- Was ist Zeigerunterstützung? ! ---- Was ist die Schnittstellenunterstützung? ! --- Was ist die Entsprechung von Scheiben? ! ---- Was ist die Entsprechung des Typalias (neuer Typ)? ! ---- Was ist Einbettungsunterstützung? ! ---- Was ist die Entsprechung von nicht konvertierbaren Feldern? ! --- Unterstützt Notationsschwankungen (Id, ID, ...) ! --- Unterstützt es mehrere Argumentfunktionen? ! --- Was passiert, wenn eine neue handschriftliche Funktion ein zusätzliches Argument erfordert? ! ---- Funktioniert es, wenn Sie eine Funktion verwenden möchten, die Sie beim Auslassen der Besetzung definiert haben? ->
Recommended Posts