Updated vednor files

This commit is contained in:
Serguei Bezverkhi
2018-02-15 08:50:31 -05:00
parent 18a4ce4439
commit 1f1e8cea37
3299 changed files with 834 additions and 1051200 deletions

View File

@ -1,9 +0,0 @@
build:
go get golang.org/x/tools/cmd/goimports
go install github.com/googleapis/gnostic
go install github.com/googleapis/gnostic/plugins/gnostic-go-generator
rm -f $(GOPATH)/bin/gnostic-go-client $(GOPATH)/bin/gnostic-go-server
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-client
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-server

View File

@ -1,18 +0,0 @@
# Go Generator Plugin
This directory contains a `gnostic` plugin that can be used to generate a Go client library and scaffolding for a Go server for an API with an OpenAPI description.
The plugin can be invoked like this:
gnostic bookstore.json --go-generator-out=bookstore
`bookstore` is the name of a directory where the generated code will be written.
`bookstore` will also be the package name used for generated code.
By default, both client and server code will be generated. If the `gnostic-go-generator` binary is also linked from the names `gnostic-go-client` and `gnostic-go-server`, then only client or only server code can be generated as follows:
gnostic bookstore.json --go-client-out=bookstore
gnostic bookstore.json --go-server-out=bookstore
For example usage, see the [examples/v2.0/bookstore](examples/v2.0/bookstore) directory.

View File

@ -1,31 +0,0 @@
# googleauth
This directory contains support code that can be used to get an OAuth2 token for a Google API user.
It is designed to work on computers with attached displays.
Use it to write command-line tools and test programs that call Google APIs.
## Instructions
Import this package and make the following call to request a token.
client, err := googleauth.NewOAuth2Client(scopes)
`scopes` should be a string containing the OAuth scopes needed by the APIs to be called.
For example, the URL Shortener API would require "https://www.googleapis.com/auth/urlshortener".
This call will then open a local browser that will redirect to a Google signin page
with information about the app that is requesting a token.
## Application Credentials
To use this package, you need to download a "client secrets" file and
save it as `client_secrets.json` in the directory where your tool is run.
To get this file, visit the {{ Google Cloud Console }}{{ https://cloud.google.com/console }}
and create a project. Then go to the API Manager to enable the APIs that you want to use
and create OAuth2 credentials. You'll then be able to download these credentials
as JSON. Save this file as `client_secrets.json`
For more information about the `client_secrets.json` file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets

View File

@ -1,220 +0,0 @@
//
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package googleauth
import (
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"runtime"
"golang.org/x/net/context"
"golang.org/x/oauth2"
)
const missingClientSecretsMessage = `
Please configure OAuth 2.0
To make this sample run, you need to populate the client_secrets.json file
found at:
%v
with information from the {{ Google Cloud Console }}
{{ https://cloud.google.com/console }}
For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
`
var (
clientSecretsFile = flag.String("secrets", "client_secrets.json", "Client Secrets configuration")
cacheFile = flag.String("cache", "request.token", "Token cache file")
)
// ClientConfig is a data structure definition for the client_secrets.json file.
// The code unmarshals the JSON configuration file into this structure.
type ClientConfig struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
RedirectURIs []string `json:"redirect_uris"`
AuthURI string `json:"auth_uri"`
TokenURI string `json:"token_uri"`
}
// Config is a root-level configuration object.
type Config struct {
Installed ClientConfig `json:"installed"`
Web ClientConfig `json:"web"`
}
// openURL opens a browser window to the specified location.
// This code originally appeared at:
// http://stackoverflow.com/questions/10377243/how-can-i-launch-a-process-that-is-not-a-file-in-go
func openURL(url string) error {
var err error
switch runtime.GOOS {
case "linux":
err = exec.Command("xdg-open", url).Start()
case "windows":
err = exec.Command("rundll32", "url.dll,FileProtocolHandler", "http://localhost:4001/").Start()
case "darwin":
err = exec.Command("open", url).Start()
default:
err = fmt.Errorf("Cannot open URL %s on this platform", url)
}
return err
}
// readConfig reads the configuration from clientSecretsFile.
// It returns an oauth configuration object for use with the Google API client.
func readConfig(scopes []string) (*oauth2.Config, error) {
// Read the secrets file
data, err := ioutil.ReadFile(*clientSecretsFile)
if err != nil {
pwd, _ := os.Getwd()
fullPath := filepath.Join(pwd, *clientSecretsFile)
return nil, fmt.Errorf(missingClientSecretsMessage, fullPath)
}
cfg := new(Config)
err = json.Unmarshal(data, &cfg)
if err != nil {
return nil, err
}
var redirectURI string
if len(cfg.Web.RedirectURIs) > 0 {
redirectURI = cfg.Web.RedirectURIs[0]
} else if len(cfg.Installed.RedirectURIs) > 0 {
redirectURI = cfg.Installed.RedirectURIs[0]
} else {
return nil, errors.New("Must specify a redirect URI in config file or when creating OAuth client")
}
return &oauth2.Config{
ClientID: cfg.Installed.ClientID,
ClientSecret: cfg.Installed.ClientSecret,
Scopes: scopes,
Endpoint: oauth2.Endpoint{cfg.Installed.AuthURI, cfg.Installed.TokenURI},
RedirectURL: redirectURI,
}, nil
}
// startWebServer starts a web server that listens on http://localhost:8080.
// The webserver waits for an oauth code in the three-legged auth flow.
func startWebServer() (codeCh chan string, err error) {
listener, err := net.Listen("tcp", "localhost:8080")
if err != nil {
return nil, err
}
codeCh = make(chan string)
go http.Serve(listener, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
code := r.FormValue("code")
codeCh <- code // send code to OAuth flow
listener.Close()
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "Received code: %v\r\nYou can now safely close this browser window.", code)
}))
return codeCh, nil
}
// NewOAuth2Client takes the user through the three-legged OAuth flow.
// It opens a browser in the native OS or outputs a URL, then blocks until
// the redirect completes to the /oauth2callback URI.
// It returns an instance of an HTTP client that can be passed to the
// constructor of an OAuth client.
// scopes is a variable number of OAuth scopes
func NewOAuth2Client(scopes ...string) (*http.Client, error) {
var ctx context.Context
tokenSource, err := NewOAuth2TokenSource(scopes...)
if err == nil {
return oauth2.NewClient(ctx, tokenSource), nil
}
return nil, err
}
// NewOAuth2TokenSource takes the user through the three-legged OAuth flow.
// It opens a browser in the native OS or outputs a URL, then blocks until
// the redirect completes to the /oauth2callback URI.
// It returns an instance of an OAuth token source that can be passed to the
// constructor of an OAuth client.
// scopes is a variable number of OAuth scopes
func NewOAuth2TokenSource(scopes ...string) (oauth2.TokenSource, error) {
config, err := readConfig(scopes)
if err != nil {
msg := fmt.Sprintf("Cannot read configuration file: %v", err)
return nil, errors.New(msg)
}
var ctx context.Context
// Try to read the token from the cache file.
// If an error occurs, do the three-legged OAuth flow because
// the token is invalid or doesn't exist.
//token, err := config.TokenCache.Token()
var token *oauth2.Token
data, err := ioutil.ReadFile(*cacheFile)
if err == nil {
err = json.Unmarshal(data, &token)
}
if (err != nil) || !token.Valid() {
// Start web server.
// This is how this program receives the authorization code
// when the browser redirects.
codeCh, err := startWebServer()
if err != nil {
return nil, err
}
// Open url in browser
url := config.AuthCodeURL("")
err = openURL(url)
if err != nil {
fmt.Println("Visit the URL below to get a code.",
" This program will pause until the site is visted.")
} else {
fmt.Println("Your browser has been opened to an authorization URL.",
" This program will resume once authorization has been provided.\n")
}
fmt.Println(url)
// Wait for the web server to get the code.
code := <-codeCh
// This code caches the authorization code on the local
// filesystem, if necessary, as long as the TokenCache
// attribute in the config is set.
token, err = config.Exchange(ctx, code)
if err != nil {
return nil, err
}
data, err := json.Marshal(token)
ioutil.WriteFile(*cacheFile, data, 0644)
}
return oauth2.StaticTokenSource(token), nil
}

View File

@ -1,4 +0,0 @@
all:
gnostic swagger.yaml --go-client-out=apis_guru
go install

View File

@ -1,41 +0,0 @@
package main
import (
"fmt"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/apis_guru/apis_guru"
"sort"
)
func main() {
c := apis_guru.NewClient("http://api.apis.guru/v2")
metrics, err := c.GetMetrics()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", metrics)
apis, err := c.ListAPIs()
if err != nil {
panic(err)
}
keys := make([]string, 0)
for key, _ := range *apis.OK {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
api := (*apis.OK)[key]
versions := make([]string, 0)
for key, _ := range api.Versions {
versions = append(versions, key)
}
sort.Strings(versions)
fmt.Printf("[%s]:%+v\n", key, versions)
}
api := (*apis.OK)["xkcd.com"].Versions["1.0.0"]
fmt.Printf("%+v\n", api.SwaggerUrl)
}

View File

@ -1,186 +0,0 @@
swagger: '2.0'
schemes:
- https
host: api.apis.guru
basePath: /v2/
info:
contact:
email: founders@apis.guru
name: APIs.guru
url: 'http://APIs.guru'
description: |
Wikipedia for Web APIs. Repository of API specs in OpenAPI(fka Swagger) 2.0 format.
**Warning**: If you want to be notified about changes in advance please subscribe to our [Gitter channel](https://gitter.im/APIs-guru/api-models).
Client sample: [[Demo]](https://apis.guru/simple-ui) [[Repo]](https://github.com/APIs-guru/simple-ui)
license:
name: CC0 1.0
url: 'https://github.com/APIs-guru/api-models#licenses'
title: APIs.guru
version: '2.0'
x-logo:
url: 'https://apis.guru/branding/logo_vertical.svg'
externalDocs:
url: 'https://github.com/APIs-guru/api-models/blob/master/API.md'
produces:
- application/json
security: []
paths:
/list.json:
get:
description: |
List all APIs in the directory.
Returns links to OpenAPI specification for each API in the directory.
If API exist in multiply versions `preferred` one is explicitly marked.
Some basic info from OpenAPI spec is cached inside each object.
This allows to generate some simple views without need to fetch OpenAPI spec for each API.
operationId: listAPIs
responses:
'200':
description: OK
schema:
$ref: '#/definitions/APIs'
summary: List all APIs
/metrics.json:
get:
description: |
Some basic metrics for the entire directory.
Just stunning numbers to put on a front page and are intended purely for WoW effect :)
operationId: getMetrics
responses:
'200':
description: OK
schema:
$ref: '#/definitions/Metrics'
summary: Get basic metrics
definitions:
API:
additionalProperties: false
description: Meta information about API
properties:
added:
description: Timestamp when the API was first added to the directory
format: date-time
type: string
preferred:
description: Recommended version
type: string
versions:
additionalProperties:
$ref: '#/definitions/ApiVersion'
description: List of supported versions of the API
minProperties: 1
type: object
required:
- added
- preferred
- versions
type: object
APIs:
additionalProperties:
$ref: '#/definitions/API'
description: |
List of API details.
It is a JSON object with API IDs(`<provider>[:<service>]`) as keys.
example:
'googleapis.com:drive':
added: '2015-02-22T20:00:45.000Z'
preferred: v3
versions:
v2:
added: '2015-02-22T20:00:45.000Z'
info:
title: Drive
version: v2
x-apiClientRegistration:
url: 'https://console.developers.google.com'
x-logo:
url: 'https://api.apis.guru/v2/cache/logo/https_www.gstatic.com_images_icons_material_product_2x_drive_32dp.png'
x-origin:
format: google
url: 'https://www.googleapis.com/discovery/v1/apis/drive/v2/rest'
version: v1
x-preferred: false
x-providerName: googleapis.com
x-serviceName: drive
swaggerUrl: 'https://api.apis.guru/v2/specs/googleapis.com/drive/v2/swagger.json'
swaggerYamlUrl: 'https://api.apis.guru/v2/specs/googleapis.com/drive/v2/swagger.yaml'
updated: '2016-06-17T00:21:44.000Z'
v3:
added: '2015-12-12T00:25:13.000Z'
info:
title: Drive
version: v3
x-apiClientRegistration:
url: 'https://console.developers.google.com'
x-logo:
url: 'https://api.apis.guru/v2/cache/logo/https_www.gstatic.com_images_icons_material_product_2x_drive_32dp.png'
x-origin:
format: google
url: 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest'
version: v1
x-preferred: true
x-providerName: googleapis.com
x-serviceName: drive
swaggerUrl: 'https://api.apis.guru/v2/specs/googleapis.com/drive/v3/swagger.json'
swaggerYamlUrl: 'https://api.apis.guru/v2/specs/googleapis.com/drive/v3/swagger.yaml'
updated: '2016-06-17T00:21:44.000Z'
minProperties: 1
type: object
ApiVersion:
additionalProperties: false
properties:
added:
description: Timestamp when the version was added
format: date-time
type: string
info:
description: Copy of `info` section from Swagger spec
minProperties: 1
type: object
swaggerUrl:
description: URL to Swagger spec in JSON format
format: url
type: string
swaggerYamlUrl:
description: URL to Swagger spec in YAML format
format: url
type: string
updated:
description: Timestamp when the version was updated
format: date-time
type: string
required:
- added
- updated
- swaggerUrl
- swaggerYamlUrl
- info
type: object
Metrics:
additionalProperties: false
description: List of basic metrics
example:
numAPIs: 238
numEndpoints: 6448
numSpecs: 302
properties:
numAPIs:
description: Number of APIs
minimum: 1
type: integer
numEndpoints:
description: Total number of endpoints inside all specifications
minimum: 1
type: integer
numSpecs:
description: Number of API specifications including different versions of the same API
minimum: 1
type: integer
required:
- numSpecs
- numAPIs
- numEndpoints
type: object

View File

@ -1,20 +0,0 @@
build:
go get golang.org/x/tools/cmd/goimports
go install github.com/googleapis/gnostic
go install github.com/googleapis/gnostic/plugins/gnostic-go-generator
rm -f $(GOPATH)/bin/gnostic-go-client $(GOPATH)/bin/gnostic-go-server
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-client
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-server
all: build
gnostic bookstore.json --go-generator-out=bookstore
clean:
rm -rf bookstore bookstore.text service/service
test: all
killall service; true # ignore errors due to no matching processes
cd service; go get .; go build; ./service &
go test
killall service

View File

@ -1,23 +0,0 @@
# Bookstore Example
This directory contains an OpenAPI description of a simple bookstore API.
Use this example to try the `gnostic-go-generator` plugin, which implements
`gnostic-go-client` and `gnostic-go-server` for generating API client and
server code, respectively.
Run "make all" to build and install `gnostic` and the Go plugins.
It will generate both client and server code. The API client and
server code will be in the `bookstore` package.
The `service` directory contains additional code that completes the server.
To build and run the service, `cd service` and do the following:
go get .
go build
./service &
To test the service with the generated client, go back up to the top-level
directory and run `go test`. The test in `bookstore_test.go` uses client
code generated in `bookstore` to verify the service.

View File

@ -1,357 +0,0 @@
{
"swagger": "2.0",
"info": {
"description": "A simple Bookstore API example.",
"title": "Bookstore",
"version": "1.0.0"
},
"host": "generated-bookstore.appspot.com",
"basePath": "/",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"schemes": [
"https"
],
"paths": {
"/shelves": {
"get": {
"description": "Return all shelves in the bookstore.",
"operationId": "listShelves",
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "List of shelves in the bookstore.",
"schema": {
"$ref": "#/definitions/listShelvesResponse"
}
}
},
"security": [
]
},
"post": {
"description": "Create a new shelf in the bookstore.",
"operationId": "createShelf",
"parameters": [
{
"description": "A shelf resource to create.",
"in": "body",
"name": "shelf",
"required": true,
"schema": {
"$ref": "#/definitions/shelf"
}
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "A newly created shelf resource.",
"schema": {
"$ref": "#/definitions/shelf"
}
}
}
},
"delete": {
"description": "Delete all shelves.",
"operationId": "deleteShelves",
"responses": {
"default": {
"description": "An empty response body."
}
}
}
},
"/shelves/{shelf}": {
"get": {
"description": "Get a single shelf resource with the given ID.",
"operationId": "getShelf",
"parameters": [
{
"description": "ID of the shelf to get.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "A shelf resource.",
"schema": {
"$ref": "#/definitions/shelf"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"delete": {
"description": "Delete a single shelf with the given ID.",
"operationId": "deleteShelf",
"parameters": [
{
"description": "ID of the shelf to delete.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
}
],
"responses": {
"default": {
"description": "An empty response body."
}
}
}
},
"/shelves/{shelf}/books": {
"get": {
"description": "Return all books in a shelf with the given ID.",
"operationId": "listBooks",
"parameters": [
{
"description": "ID of the shelf whose books should be returned.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "List of books on the specified shelf.",
"schema": {
"$ref": "#/definitions/listBooksResponse"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"post": {
"description": "Create a new book on the shelf.",
"operationId": "createBook",
"parameters": [
{
"description": "ID of the shelf where the book should be created.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
},
{
"description": "Book to create.",
"in": "body",
"name": "book",
"required": true,
"schema": {
"$ref": "#/definitions/book"
}
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "A newly created book resource.",
"schema": {
"$ref": "#/definitions/book"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/shelves/{shelf}/books/{book}": {
"get": {
"description": "Get a single book with a given ID from a shelf.",
"operationId": "getBook",
"parameters": [
{
"description": "ID of the shelf from which to get the book.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
},
{
"description": "ID of the book to get from the shelf.",
"format": "int64",
"in": "path",
"name": "book",
"required": true,
"type": "integer"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": "A book resource.",
"schema": {
"$ref": "#/definitions/book"
}
},
"default": {
"description": "unexpected error",
"schema": {
"$ref": "#/definitions/error"
}
}
}
},
"delete": {
"description": "Delete a single book with a given ID from a shelf.",
"operationId": "deleteBook",
"parameters": [
{
"description": "ID of the shelf from which to delete the book.",
"format": "int64",
"in": "path",
"name": "shelf",
"required": true,
"type": "integer"
},
{
"description": "ID of the book to delete from the shelf.",
"format": "int64",
"in": "path",
"name": "book",
"required": true,
"type": "integer"
}
],
"responses": {
"default": {
"description": "An empty response body."
}
}
}
}
},
"definitions": {
"book": {
"properties": {
"author": {
"type": "string"
},
"name": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"name",
"author",
"title"
]
},
"listBooksResponse": {
"properties": {
"books": {
"items": {
"$ref": "#/definitions/book"
},
"type": "array"
}
},
"required": [
"books"
],
"type": "object"
},
"listShelvesResponse": {
"properties": {
"shelves": {
"items": {
"$ref": "#/definitions/shelf"
},
"type": "array"
}
},
"type": "object"
},
"shelf": {
"properties": {
"name": {
"type": "string"
},
"theme": {
"type": "string"
}
},
"required": [
"name",
"theme"
]
},
"error": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
}
}
},
"security": [
{
"api_key": [
]
}
],
"securityDefinitions": {
"api_key": {
"in": "query",
"name": "key",
"type": "apiKey"
}
}
}

View File

@ -1,239 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"fmt"
"net/http"
"strings"
"testing"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore"
)
const service = "http://localhost:8080"
//const service = "http://generated-bookstore.appspot.com"
func TestBookstore(t *testing.T) {
// create a client
b := bookstore.NewClient(service, nil)
// reset the service by deleting all shelves
{
err := b.DeleteShelves()
if err != nil {
t.Log("delete shelves failed")
t.Fail()
}
}
// verify that the service has no shelves
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if (response == nil) || (response.OK == nil) || (response.OK.Shelves != nil) {
t.Log(fmt.Sprintf("list shelves failed %+v", response.OK))
t.Log(fmt.Sprintf("list shelves failed len=%d", len(response.OK.Shelves)))
t.Fail()
}
}
// attempting to get a shelf should return an error
{
_, err := b.GetShelf(1)
if err == nil {
t.Log("get shelf failed to return an error")
t.Fail()
}
}
// attempting to get a book should return an error
{
_, err := b.GetBook(1, 2)
if err == nil {
t.Log("get book failed to return an error")
t.Fail()
}
}
// add a shelf
{
var shelf bookstore.Shelf
shelf.Theme = "mysteries"
response, err := b.CreateShelf(shelf)
if err != nil {
t.Log("create shelf mysteries failed")
t.Fail()
}
if (response.OK.Name != "shelves/1") ||
(response.OK.Theme != "mysteries") {
t.Log("create shelf mysteries failed")
t.Fail()
}
}
// add another shelf
{
var shelf bookstore.Shelf
shelf.Theme = "comedies"
response, err := b.CreateShelf(shelf)
if err != nil {
t.Log("create shelf comedies failed")
t.Fail()
}
if (response.OK.Name != "shelves/2") ||
(response.OK.Theme != "comedies") {
t.Log("create shelf comedies failed")
t.Fail()
}
}
// get the first shelf that was added
{
response, err := b.GetShelf(1)
if err != nil {
t.Log("get shelf mysteries failed")
t.Fail()
}
if (response.OK.Name != "shelves/1") ||
(response.OK.Theme != "mysteries") {
t.Log("get shelf mysteries failed")
t.Fail()
}
}
// list shelves and verify that there are 2
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if len(response.OK.Shelves) != 2 {
t.Log("list shelves failed")
t.Fail()
}
}
// delete a shelf
{
err := b.DeleteShelf(2)
if err != nil {
t.Log("delete shelf failed")
t.Fail()
}
}
// list shelves and verify that there is only 1
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if len(response.OK.Shelves) != 1 {
t.Log("list shelves failed")
t.Fail()
}
}
// list books on a shelf, verify that there are none
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 0 {
t.Log("list books failed")
t.Fail()
}
}
// create a book
{
var book bookstore.Book
book.Author = "Agatha Christie"
book.Title = "And Then There Were None"
_, err := b.CreateBook(1, book)
if err != nil {
t.Log("create book failed")
t.Fail()
}
}
// create another book
{
var book bookstore.Book
book.Author = "Agatha Christie"
book.Title = "Murder on the Orient Express"
_, err := b.CreateBook(1, book)
if err != nil {
t.Log("create book failed")
t.Fail()
}
}
// get the first book that was added
{
_, err := b.GetBook(1, 1)
if err != nil {
t.Log("get book failed")
t.Fail()
}
}
// list the books on a shelf and verify that there are 2
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 2 {
t.Log("list books failed")
t.Fail()
}
}
// delete a book
{
err := b.DeleteBook(1, 2)
if err != nil {
t.Log("delete book failed")
t.Fail()
}
}
// list the books on a shelf and verify that is only 1
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 1 {
t.Log("list books failed")
t.Fail()
}
}
// verify the handling of a badly-formed request
{
req, err := http.NewRequest("POST", service+"/shelves", strings.NewReader(""))
if err != nil {
t.Log("bad request failed")
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
// we expect a 400 (Bad Request) code
if resp.StatusCode != 400 {
t.Log("bad request failed")
t.Fail()
}
return
}
}

View File

@ -1,9 +0,0 @@
application: bookstore
version: 1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
- url: /
static_dir: static

View File

@ -1,27 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore"
)
// init() is called when the package is loaded
// this allows this app to be trivially deployed to Google App Engine, which does not call main()
func init() {
bookstore.Initialize(NewService())
}

View File

@ -1,34 +0,0 @@
// +build !appengine
// This file is omitted when the app is built for Google App Engine
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"log"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore"
)
func main() {
err := bookstore.ServeHTTP(":8080")
if err != nil {
log.Printf("%v", err)
}
}

View File

@ -1,195 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"errors"
"fmt"
"net/http"
"sync"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/bookstore/bookstore"
)
//
// The Service type implements a bookstore service.
// All objects are managed in an in-memory non-persistent store.
//
type Service struct {
// shelves are stored in a map keyed by shelf id
// books are stored in a two level map, keyed first by shelf id and then by book id
Shelves map[int64]*bookstore.Shelf
Books map[int64]map[int64]*bookstore.Book
LastShelfID int64 // the id of the last shelf that was added
LastBookID int64 // the id of the last book that was added
Mutex sync.Mutex // global mutex to synchronize service access
}
func NewService() *Service {
return &Service{
Shelves: make(map[int64]*bookstore.Shelf),
Books: make(map[int64]map[int64]*bookstore.Book),
}
}
func (service *Service) ListShelves(responses *bookstore.ListShelvesResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// copy shelf ids from Shelves map keys
shelves := make([]bookstore.Shelf, 0, len(service.Shelves))
for _, shelf := range service.Shelves {
shelves = append(shelves, *shelf)
}
response := &bookstore.ListShelvesResponse{}
response.Shelves = shelves
(*responses).OK = response
return err
}
func (service *Service) CreateShelf(parameters *bookstore.CreateShelfParameters, responses *bookstore.CreateShelfResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// assign an id and name to a shelf and add it to the Shelves map.
shelf := parameters.Shelf
service.LastShelfID++
sid := service.LastShelfID
shelf.Name = fmt.Sprintf("shelves/%d", sid)
service.Shelves[sid] = &shelf
(*responses).OK = &shelf
return err
}
func (service *Service) DeleteShelves() (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete everything by reinitializing the Shelves and Books maps.
service.Shelves = make(map[int64]*bookstore.Shelf)
service.Books = make(map[int64]map[int64]*bookstore.Book)
service.LastShelfID = 0
service.LastBookID = 0
return nil
}
func (service *Service) GetShelf(parameters *bookstore.GetShelfParameters, responses *bookstore.GetShelfResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// look up a shelf from the Shelves map.
shelf, err := service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
} else {
(*responses).OK = shelf
return nil
}
}
func (service *Service) DeleteShelf(parameters *bookstore.DeleteShelfParameters) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete a shelf by removing the shelf from the Shelves map and the associated books from the Books map.
delete(service.Shelves, parameters.Shelf)
delete(service.Books, parameters.Shelf)
return nil
}
func (service *Service) ListBooks(parameters *bookstore.ListBooksParameters, responses *bookstore.ListBooksResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// list the books in a shelf
_, err = service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
}
shelfBooks := service.Books[parameters.Shelf]
books := make([]bookstore.Book, 0, len(shelfBooks))
for _, book := range shelfBooks {
books = append(books, *book)
}
response := &bookstore.ListBooksResponse{}
response.Books = books
(*responses).OK = response
return nil
}
func (service *Service) CreateBook(parameters *bookstore.CreateBookParameters, responses *bookstore.CreateBookResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// return "not found" if the shelf doesn't exist
shelf, err := service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
}
// assign an id and name to a book and add it to the Books map.
service.LastBookID++
bid := service.LastBookID
book := parameters.Book
book.Name = fmt.Sprintf("%s/books/%d", shelf.Name, bid)
if service.Books[parameters.Shelf] == nil {
service.Books[parameters.Shelf] = make(map[int64]*bookstore.Book)
}
service.Books[parameters.Shelf][bid] = &book
(*responses).OK = &book
return err
}
func (service *Service) GetBook(parameters *bookstore.GetBookParameters, responses *bookstore.GetBookResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// get a book from the Books map
book, err := service.getBook(parameters.Shelf, parameters.Book)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
} else {
(*responses).OK = book
}
return nil
}
func (service *Service) DeleteBook(parameters *bookstore.DeleteBookParameters) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete a book by removing the book from the Books map.
delete(service.Books[parameters.Shelf], parameters.Book)
return nil
}
// internal helpers
func (service *Service) getShelf(sid int64) (shelf *bookstore.Shelf, err error) {
shelf, ok := service.Shelves[sid]
if !ok {
return nil, errors.New(fmt.Sprintf("Couldn't find shelf %d", sid))
} else {
return shelf, nil
}
}
func (service *Service) getBook(sid int64, bid int64) (book *bookstore.Book, err error) {
_, err = service.getShelf(sid)
if err != nil {
return nil, err
}
book, ok := service.Books[sid][bid]
if !ok {
return nil, errors.New(fmt.Sprintf("Couldn't find book %d on shelf %d", bid, sid))
} else {
return book, nil
}
}

View File

@ -1,3 +0,0 @@
all:
gnostic swagger.json --go-client-out=xkcd
go install

View File

@ -1,22 +0,0 @@
package main
import (
"fmt"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v2.0/xkcd/xkcd"
)
func main() {
c := xkcd.NewClient("http://xkcd.com")
comic, err := c.Get_info_0_json()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", comic)
comic, err = c.Get_comicId_info_0_json(1800)
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", comic)
}

View File

@ -1,111 +0,0 @@
{
"swagger": "2.0",
"schemes": [
"http"
],
"host": "xkcd.com",
"basePath": "/",
"info": {
"description": "Webcomic of romance, sarcasm, math, and language.",
"title": "XKCD",
"version": "1.0.0",
"x-apisguru-categories": [
"media"
],
"x-logo": {
"url": "https://api.apis.guru/v2/cache/logo/http_imgs.xkcd.com_static_terrible_small_logo.png"
},
"x-origin": {
"format": "swagger",
"url": "https://raw.githubusercontent.com/APIs-guru/unofficial_openapi_specs/master/xkcd.com/1.0.0/swagger.yaml",
"version": "2.0"
},
"x-preferred": true,
"x-providerName": "xkcd.com",
"x-tags": [
"humor",
"comics"
],
"x-unofficialSpec": true
},
"externalDocs": {
"url": "https://xkcd.com/json.html"
},
"securityDefinitions": {},
"paths": {
"/info.0.json": {
"get": {
"description": "Fetch current comic and metadata.\n",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/comic"
}
}
}
}
},
"/{comicId}/info.0.json": {
"get": {
"description": "Fetch comics and metadata by comic id.\n",
"parameters": [
{
"in": "path",
"name": "comicId",
"required": true,
"type": "number"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/comic"
}
}
}
}
}
},
"definitions": {
"comic": {
"properties": {
"alt": {
"type": "string"
},
"day": {
"type": "string"
},
"img": {
"type": "string"
},
"link": {
"type": "string"
},
"month": {
"type": "string"
},
"news": {
"type": "string"
},
"num": {
"type": "number"
},
"safe_title": {
"type": "string"
},
"title": {
"type": "string"
},
"transcript": {
"type": "string"
},
"year": {
"type": "string"
}
},
"type": "object"
}
}
}

View File

@ -1,20 +0,0 @@
build:
go get golang.org/x/tools/cmd/goimports
go install github.com/googleapis/gnostic
go install github.com/googleapis/gnostic/plugins/gnostic-go-generator
rm -f $(GOPATH)/bin/gnostic-go-client $(GOPATH)/bin/gnostic-go-server
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-client
ln -s $(GOPATH)/bin/gnostic-go-generator $(GOPATH)/bin/gnostic-go-server
all: build
gnostic bookstore.json --go-generator-out=bookstore
clean:
rm -rf bookstore bookstore.text service/service
test: all
killall service; true # ignore errors due to no matching processes
cd service; go get .; go build; ./service &
go test
killall service

View File

@ -1,23 +0,0 @@
# Bookstore Example
This directory contains an OpenAPI description of a simple bookstore API.
Use this example to try the `gnostic-go-generator` plugin, which implements
`gnostic-go-client` and `gnostic-go-server` for generating API client and
server code, respectively.
Run "make all" to build and install `gnostic` and the Go plugins.
It will generate both client and server code. The API client and
server code will be in the `bookstore` package.
The `service` directory contains additional code that completes the server.
To build and run the service, `cd service` and do the following:
go get .
go build
./service &
To test the service with the generated client, go back up to the top-level
directory and run `go test`. The test in `bookstore_test.go` uses client
code generated in `bookstore` to verify the service.

View File

@ -1,392 +0,0 @@
{
"openapi": "3.0.0",
"servers": [
{
"url": "https://generated-bookstore.appspot.com/"
}
],
"info": {
"description": "A simple Bookstore API example.",
"title": "Bookstore",
"version": "1.0.0"
},
"paths": {
"/shelves": {
"get": {
"description": "Return all shelves in the bookstore.",
"operationId": "listShelves",
"responses": {
"200": {
"description": "List of shelves in the bookstore.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/listShelvesResponse"
}
}
}
}
},
"security": []
},
"post": {
"description": "Create a new shelf in the bookstore.",
"operationId": "createShelf",
"responses": {
"200": {
"description": "A newly created shelf resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/shelf"
}
}
}
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/shelf"
}
}
},
"description": "A shelf resource to create.",
"required": true
}
},
"delete": {
"description": "Delete all shelves.",
"operationId": "deleteShelves",
"responses": {
"default": {
"description": "An empty response body."
}
}
}
},
"/shelves/{shelf}": {
"get": {
"description": "Get a single shelf resource with the given ID.",
"operationId": "getShelf",
"parameters": [
{
"description": "ID of the shelf to get.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "A shelf resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/shelf"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/error"
}
}
}
}
}
},
"delete": {
"description": "Delete a single shelf with the given ID.",
"operationId": "deleteShelf",
"parameters": [
{
"description": "ID of the shelf to delete.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"default": {
"description": "An empty response body."
}
}
}
},
"/shelves/{shelf}/books": {
"get": {
"description": "Return all books in a shelf with the given ID.",
"operationId": "listBooks",
"parameters": [
{
"description": "ID of the shelf whose books should be returned.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "List of books on the specified shelf.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/listBooksResponse"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/error"
}
}
}
}
}
},
"post": {
"description": "Create a new book on the shelf.",
"operationId": "createBook",
"parameters": [
{
"description": "ID of the shelf where the book should be created.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "A newly created book resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/book"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/error"
}
}
}
}
},
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/book"
}
}
},
"description": "Book to create.",
"required": true
}
}
},
"/shelves/{shelf}/books/{book}": {
"get": {
"description": "Get a single book with a given ID from a shelf.",
"operationId": "getBook",
"parameters": [
{
"description": "ID of the shelf from which to get the book.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
},
{
"description": "ID of the book to get from the shelf.",
"in": "path",
"name": "book",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"200": {
"description": "A book resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/book"
}
}
}
},
"default": {
"description": "unexpected error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/error"
}
}
}
}
}
},
"delete": {
"description": "Delete a single book with a given ID from a shelf.",
"operationId": "deleteBook",
"parameters": [
{
"description": "ID of the shelf from which to delete the book.",
"in": "path",
"name": "shelf",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
},
{
"description": "ID of the book to delete from the shelf.",
"in": "path",
"name": "book",
"required": true,
"schema": {
"type": "integer",
"format": "int64"
}
}
],
"responses": {
"default": {
"description": "An empty response body."
}
}
}
}
},
"security": [
{
"api_key": []
}
],
"components": {
"schemas": {
"book": {
"properties": {
"author": {
"type": "string"
},
"name": {
"type": "string"
},
"title": {
"type": "string"
}
},
"required": [
"name",
"author",
"title"
],
"type": "object"
},
"listBooksResponse": {
"properties": {
"books": {
"items": {
"$ref": "#/components/schemas/book"
},
"type": "array"
}
},
"required": [
"books"
],
"type": "object"
},
"listShelvesResponse": {
"properties": {
"shelves": {
"items": {
"$ref": "#/components/schemas/shelf"
},
"type": "array"
}
},
"type": "object"
},
"shelf": {
"properties": {
"name": {
"type": "string"
},
"theme": {
"type": "string"
}
},
"required": [
"name",
"theme"
],
"type": "object"
},
"error": {
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "integer",
"format": "int32"
},
"message": {
"type": "string"
}
},
"type": "object"
}
},
"securitySchemes": {
"api_key": {
"in": "query",
"name": "key",
"type": "apiKey"
}
}
}
}

View File

@ -1,239 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package test
import (
"fmt"
"net/http"
"strings"
"testing"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v3.0/bookstore/bookstore"
)
const service = "http://localhost:8080"
//const service = "http://generated-bookstore.appspot.com"
func TestBookstore(t *testing.T) {
// create a client
b := bookstore.NewClient(service, nil)
// reset the service by deleting all shelves
{
err := b.DeleteShelves()
if err != nil {
t.Log("delete shelves failed")
t.Fail()
}
}
// verify that the service has no shelves
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if (response == nil) || (response.OK == nil) || (response.OK.Shelves != nil) {
t.Log(fmt.Sprintf("list shelves failed %+v", response.OK))
t.Log(fmt.Sprintf("list shelves failed len=%d", len(response.OK.Shelves)))
t.Fail()
}
}
// attempting to get a shelf should return an error
{
response, err := b.GetShelf(1)
if err == nil {
t.Logf("get shelf failed to return an error (%+v)", response.OK)
t.Fail()
}
}
// attempting to get a book should return an error
{
response, err := b.GetBook(1, 2)
if err == nil {
t.Logf("get book failed to return an error (%+v)", response.OK)
t.Fail()
}
}
// add a shelf
{
var shelf bookstore.Shelf
shelf.Theme = "mysteries"
response, err := b.CreateShelf(shelf)
if err != nil {
t.Log("create shelf mysteries failed")
t.Fail()
}
if (response.OK.Name != "shelves/1") ||
(response.OK.Theme != "mysteries") {
t.Log("create shelf mysteries failed")
t.Fail()
}
}
// add another shelf
{
var shelf bookstore.Shelf
shelf.Theme = "comedies"
response, err := b.CreateShelf(shelf)
if err != nil {
t.Log("create shelf comedies failed")
t.Fail()
}
if (response.OK.Name != "shelves/2") ||
(response.OK.Theme != "comedies") {
t.Log("create shelf comedies failed")
t.Fail()
}
}
// get the first shelf that was added
{
response, err := b.GetShelf(1)
if err != nil {
t.Log("get shelf mysteries failed")
t.Fail()
}
if (response.OK.Name != "shelves/1") ||
(response.OK.Theme != "mysteries") {
t.Log("get shelf mysteries failed")
t.Fail()
}
}
// list shelves and verify that there are 2
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if len(response.OK.Shelves) != 2 {
t.Log("list shelves failed")
t.Fail()
}
}
// delete a shelf
{
err := b.DeleteShelf(2)
if err != nil {
t.Log("delete shelf failed")
t.Fail()
}
}
// list shelves and verify that there is only 1
{
response, err := b.ListShelves()
if err != nil {
t.Log("list shelves failed")
t.Fail()
}
if len(response.OK.Shelves) != 1 {
t.Log("list shelves failed")
t.Fail()
}
}
// list books on a shelf, verify that there are none
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 0 {
t.Log("list books failed")
t.Fail()
}
}
// create a book
{
var book bookstore.Book
book.Author = "Agatha Christie"
book.Title = "And Then There Were None"
_, err := b.CreateBook(1, book)
if err != nil {
t.Log("create book failed")
t.Fail()
}
}
// create another book
{
var book bookstore.Book
book.Author = "Agatha Christie"
book.Title = "Murder on the Orient Express"
_, err := b.CreateBook(1, book)
if err != nil {
t.Log("create book failed")
t.Fail()
}
}
// get the first book that was added
{
_, err := b.GetBook(1, 1)
if err != nil {
t.Log("get book failed")
t.Fail()
}
}
// list the books on a shelf and verify that there are 2
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 2 {
t.Log("list books failed")
t.Fail()
}
}
// delete a book
{
err := b.DeleteBook(1, 2)
if err != nil {
t.Log("delete book failed")
t.Fail()
}
}
// list the books on a shelf and verify that is only 1
{
response, err := b.ListBooks(1)
if err != nil {
t.Log("list books failed")
t.Fail()
}
if len(response.OK.Books) != 1 {
t.Log("list books failed")
t.Fail()
}
}
// verify the handling of a badly-formed request
{
req, err := http.NewRequest("POST", service+"/shelves", strings.NewReader(""))
if err != nil {
t.Log("bad request failed")
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return
}
// we expect a 400 (Bad Request) code
if resp.StatusCode != 400 {
t.Log("bad request failed")
t.Fail()
}
return
}
}

View File

@ -1,9 +0,0 @@
application: bookstore
version: 1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
- url: /
static_dir: static

View File

@ -1,27 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v3.0/bookstore/bookstore"
)
// init() is called when the package is loaded
// this allows this app to be trivially deployed to Google App Engine, which does not call main()
func init() {
bookstore.Initialize(NewService())
}

View File

@ -1,34 +0,0 @@
// +build !appengine
// This file is omitted when the app is built for Google App Engine
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"log"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v3.0/bookstore/bookstore"
)
func main() {
err := bookstore.ServeHTTP(":8080")
if err != nil {
log.Printf("%v", err)
}
}

View File

@ -1,195 +0,0 @@
/*
Copyright 2017 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"errors"
"fmt"
"net/http"
"sync"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v3.0/bookstore/bookstore"
)
//
// The Service type implements a bookstore service.
// All objects are managed in an in-memory non-persistent store.
//
type Service struct {
// shelves are stored in a map keyed by shelf id
// books are stored in a two level map, keyed first by shelf id and then by book id
Shelves map[int64]*bookstore.Shelf
Books map[int64]map[int64]*bookstore.Book
LastShelfID int64 // the id of the last shelf that was added
LastBookID int64 // the id of the last book that was added
Mutex sync.Mutex // global mutex to synchronize service access
}
func NewService() *Service {
return &Service{
Shelves: make(map[int64]*bookstore.Shelf),
Books: make(map[int64]map[int64]*bookstore.Book),
}
}
func (service *Service) ListShelves(responses *bookstore.ListShelvesResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// copy shelf ids from Shelves map keys
shelves := make([]bookstore.Shelf, 0, len(service.Shelves))
for _, shelf := range service.Shelves {
shelves = append(shelves, *shelf)
}
response := &bookstore.ListShelvesResponse{}
response.Shelves = shelves
(*responses).OK = response
return err
}
func (service *Service) CreateShelf(parameters *bookstore.CreateShelfParameters, responses *bookstore.CreateShelfResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// assign an id and name to a shelf and add it to the Shelves map.
shelf := parameters.Shelf
service.LastShelfID++
sid := service.LastShelfID
shelf.Name = fmt.Sprintf("shelves/%d", sid)
service.Shelves[sid] = &shelf
(*responses).OK = &shelf
return err
}
func (service *Service) DeleteShelves() (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete everything by reinitializing the Shelves and Books maps.
service.Shelves = make(map[int64]*bookstore.Shelf)
service.Books = make(map[int64]map[int64]*bookstore.Book)
service.LastShelfID = 0
service.LastBookID = 0
return nil
}
func (service *Service) GetShelf(parameters *bookstore.GetShelfParameters, responses *bookstore.GetShelfResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// look up a shelf from the Shelves map.
shelf, err := service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
} else {
(*responses).OK = shelf
return nil
}
}
func (service *Service) DeleteShelf(parameters *bookstore.DeleteShelfParameters) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete a shelf by removing the shelf from the Shelves map and the associated books from the Books map.
delete(service.Shelves, parameters.Shelf)
delete(service.Books, parameters.Shelf)
return nil
}
func (service *Service) ListBooks(parameters *bookstore.ListBooksParameters, responses *bookstore.ListBooksResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// list the books in a shelf
_, err = service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
}
shelfBooks := service.Books[parameters.Shelf]
books := make([]bookstore.Book, 0, len(shelfBooks))
for _, book := range shelfBooks {
books = append(books, *book)
}
response := &bookstore.ListBooksResponse{}
response.Books = books
(*responses).OK = response
return nil
}
func (service *Service) CreateBook(parameters *bookstore.CreateBookParameters, responses *bookstore.CreateBookResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// return "not found" if the shelf doesn't exist
shelf, err := service.getShelf(parameters.Shelf)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
return nil
}
// assign an id and name to a book and add it to the Books map.
service.LastBookID++
bid := service.LastBookID
book := parameters.Book
book.Name = fmt.Sprintf("%s/books/%d", shelf.Name, bid)
if service.Books[parameters.Shelf] == nil {
service.Books[parameters.Shelf] = make(map[int64]*bookstore.Book)
}
service.Books[parameters.Shelf][bid] = &book
(*responses).OK = &book
return err
}
func (service *Service) GetBook(parameters *bookstore.GetBookParameters, responses *bookstore.GetBookResponses) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// get a book from the Books map
book, err := service.getBook(parameters.Shelf, parameters.Book)
if err != nil {
(*responses).Default = &bookstore.Error{Code: int32(http.StatusNotFound), Message: err.Error()}
} else {
(*responses).OK = book
}
return nil
}
func (service *Service) DeleteBook(parameters *bookstore.DeleteBookParameters) (err error) {
service.Mutex.Lock()
defer service.Mutex.Unlock()
// delete a book by removing the book from the Books map.
delete(service.Books[parameters.Shelf], parameters.Book)
return nil
}
// internal helpers
func (service *Service) getShelf(sid int64) (shelf *bookstore.Shelf, err error) {
shelf, ok := service.Shelves[sid]
if !ok {
return nil, errors.New(fmt.Sprintf("Couldn't find shelf %d", sid))
} else {
return shelf, nil
}
}
func (service *Service) getBook(sid int64, bid int64) (book *bookstore.Book, err error) {
_, err = service.getShelf(sid)
if err != nil {
return nil, err
}
book, ok := service.Books[sid][bid]
if !ok {
return nil, errors.New(fmt.Sprintf("Couldn't find book %d on shelf %d", bid, sid))
} else {
return book, nil
}
}

View File

@ -1,26 +0,0 @@
# urlshortener sample client
## Steps to run:
1. Generate the OpenAPI 3.0 description using `disco` (in the `gnostic/apps` directory).
disco get urlshortener --openapi3
2. (optional) View the JSON OpenAPI 3.0 description.
gnostic openapi3-urlshortener-v1.pb --json-out=-
3. Generate the urlshortener client.
gnostic openapi3-urlshortener-v1.pb --go-client-out=urlshortener
4. Build the client.
go install
5. Download `client_secrets.json` from the Google Cloud Developer Console.
6. Run the client
urlshortener

View File

@ -1,62 +0,0 @@
package main
import (
"fmt"
"log"
"github.com/docopt/docopt-go"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/googleauth"
"github.com/googleapis/gnostic/plugins/gnostic-go-generator/examples/v3.0/urlshortener/urlshortener"
)
func main() {
usage := `
Usage:
urlshortener get <url>
urlshortener list
urlshortener insert <url>
`
arguments, err := docopt.Parse(usage, nil, false, "URL Shortener 1.0", false)
if err != nil {
log.Fatalf("%+v", err)
}
path := "https://www.googleapis.com/urlshortener/v1" // this should be generated
client, err := googleauth.NewOAuth2Client("https://www.googleapis.com/auth/urlshortener")
if err != nil {
log.Fatalf("Error building OAuth client: %v", err)
}
c := urlshortener.NewClient(path, client)
// get
if arguments["get"].(bool) {
response, err := c.Urlshortener_Url_Get("FULL", arguments["<url>"].(string))
if err != nil {
log.Fatalf("%+v", err)
}
fmt.Println(response.Default.LongUrl)
}
// list
if arguments["list"].(bool) {
response, err := c.Urlshortener_Url_List("", "")
if err != nil {
log.Fatalf("%+v", err)
}
for _, item := range response.Default.Items {
fmt.Printf("%-40s %s\n", item.Id, item.LongUrl)
}
}
// insert
if arguments["insert"].(bool) {
var url urlshortener.Url
url.LongUrl = arguments["<url>"].(string)
response, err := c.Urlshortener_Url_Insert(url)
if err != nil {
log.Fatalf("%+v", err)
}
fmt.Printf("%+v\n", response.Default.Id)
}
}

View File

@ -1,50 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"io/ioutil"
"log"
"os"
"os/exec"
"strings"
)
// Run goimports to format and update imports statements in generated code.
func goimports(filename string, inputBytes []byte) (outputBytes []byte, err error) {
if false {
return inputBytes, nil
}
cmd := exec.Command(os.Getenv("GOPATH") + "/bin/goimports")
input, _ := cmd.StdinPipe()
output, _ := cmd.StdoutPipe()
cmderr, _ := cmd.StderrPipe()
err = cmd.Start()
if err != nil {
return
}
input.Write(inputBytes)
input.Close()
outputBytes, _ = ioutil.ReadAll(output)
errors, _ := ioutil.ReadAll(cmderr)
if len(errors) > 0 {
errors := strings.Replace(string(errors), "<standard input>", filename, -1)
log.Printf("Syntax errors in generated code:\n%s", errors)
return inputBytes, nil
}
return
}

View File

@ -1,121 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
surface "github.com/googleapis/gnostic/surface"
"unicode"
"strings"
)
type GoLanguageModel struct{}
func NewGoLanguageModel() *GoLanguageModel {
return &GoLanguageModel{}
}
// Prepare sets language-specific properties for all types and methods.
func (language *GoLanguageModel) Prepare(model *surface.Model) {
for _, t := range model.Types {
// determine the type used for Go language implementation of the type
t.TypeName = strings.Title(filteredTypeName(t.Name))
for _, f := range t.Fields {
f.FieldName = goFieldName(f.Name)
f.ParameterName = goParameterName(f.Name)
switch f.Type {
case "number":
f.NativeType = "int"
case "integer":
switch f.Format {
case "int32":
f.NativeType = "int32"
case "int64":
f.NativeType = "int64"
default:
f.NativeType = "int64"
}
case "object":
f.NativeType = "{}interface"
case "string":
f.NativeType = "string"
default:
f.NativeType = strings.Title(f.Type)
}
}
}
for _, m := range model.Methods {
m.HandlerName = "Handle" + m.Name
m.ProcessorName = m.Name
m.ClientName = m.Name
}
}
func goParameterName(name string) string {
// lowercase first letter
a := []rune(name)
a[0] = unicode.ToLower(a[0])
name = string(a)
// replace dots with underscores
name = strings.Replace(name, ".", "_", -1)
// replaces dashes with underscores
name = strings.Replace(name, "-", "_", -1)
// avoid reserved words
if name == "type" {
return "myType"
}
return name
}
func goFieldName(name string) string {
name = strings.Replace(name, ".", "_", -1)
name = strings.Replace(name, "-", "_", -1)
name = snakeCaseToCamelCaseWithCapitalizedFirstLetter(name)
// avoid integers
if name == "200" {
return "OK"
}
return name
}
func snakeCaseToCamelCaseWithCapitalizedFirstLetter(snakeCase string) (camelCase string) {
isToUpper := false
for _, runeValue := range snakeCase {
if isToUpper {
camelCase += strings.ToUpper(string(runeValue))
isToUpper = false
} else {
if runeValue == '_' {
isToUpper = true
} else {
camelCase += string(runeValue)
}
}
}
camelCase = strings.Title(camelCase)
return
}
func filteredTypeName(typeName string) (name string) {
// first take the last path segment
parts := strings.Split(typeName, "/")
name = parts[len(parts)-1]
// then take the last part of a dotted name
parts = strings.Split(name, ".")
name = parts[len(parts)-1]
return name
}

View File

@ -1,29 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import "bytes"
type LineWriter struct {
bytes.Buffer
}
func NewLineWriter() *LineWriter {
return &LineWriter{}
}
func (w *LineWriter) WriteLine(line string) {
w.WriteString(line + "\n")
}

View File

@ -1,71 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// gnostic_go_generator is a sample Gnostic plugin that generates Go
// code that supports an API.
package main
import (
"encoding/json"
"errors"
"strings"
plugins "github.com/googleapis/gnostic/plugins"
)
// This is the main function for the code generation plugin.
func main() {
env, err := plugins.NewEnvironment()
env.RespondAndExitIfError(err)
packageName := env.Request.OutputPath
// Use the name used to run the plugin to decide which files to generate.
var files []string
switch {
case strings.Contains(env.Invocation, "gnostic-go-client"):
files = []string{"client.go", "types.go", "constants.go"}
case strings.Contains(env.Invocation, "gnostic-go-server"):
files = []string{"server.go", "provider.go", "types.go", "constants.go"}
default:
files = []string{"client.go", "server.go", "provider.go", "types.go", "constants.go"}
}
// Get the code surface model.
model := env.Request.Surface
if model == nil {
err = errors.New("No generated code surface model is available.")
env.RespondAndExitIfError(err)
}
// Customize the code surface model for Go
NewGoLanguageModel().Prepare(model)
modelJSON, _ := json.MarshalIndent(model, "", " ")
modelFile := &plugins.File{Name: "model.json", Data: modelJSON}
env.Response.Files = append(env.Response.Files, modelFile)
// Create the renderer.
renderer, err := NewServiceRenderer(model)
renderer.Package = packageName
env.RespondAndExitIfError(err)
// Run the renderer to generate files and add them to the response object.
err = renderer.Render(env.Response, files)
env.RespondAndExitIfError(err)
// Return with success.
env.RespondAndExit()
}

View File

@ -1,176 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"strings"
surface "github.com/googleapis/gnostic/surface"
)
// ParameterList returns a string representation of a method's parameters
func ParameterList(parametersType *surface.Type) string {
result := ""
if parametersType != nil {
for _, field := range parametersType.Fields {
result += field.ParameterName + " " + field.NativeType + "," + "\n"
}
}
return result
}
func (renderer *Renderer) RenderClient() ([]byte, error) {
f := NewLineWriter()
f.WriteLine("// GENERATED FILE: DO NOT EDIT!")
f.WriteLine(``)
f.WriteLine("package " + renderer.Package)
// imports will be automatically added by goimports
f.WriteLine(`// Client represents an API client.`)
f.WriteLine(`type Client struct {`)
f.WriteLine(` service string`)
f.WriteLine(` APIKey string`)
f.WriteLine(` client *http.Client`)
f.WriteLine(`}`)
f.WriteLine(`// NewClient creates an API client.`)
f.WriteLine(`func NewClient(service string, c *http.Client) *Client {`)
f.WriteLine(` client := &Client{}`)
f.WriteLine(` client.service = service`)
f.WriteLine(` if c != nil {`)
f.WriteLine(` client.client = c`)
f.WriteLine(` } else {`)
f.WriteLine(` client.client = http.DefaultClient`)
f.WriteLine(` }`)
f.WriteLine(` return client`)
f.WriteLine(`}`)
for _, method := range renderer.Model.Methods {
parametersType := renderer.Model.TypeWithTypeName(method.ParametersTypeName)
responsesType := renderer.Model.TypeWithTypeName(method.ResponsesTypeName)
f.WriteLine(commentForText(method.Description))
f.WriteLine(`func (client *Client) ` + method.ClientName + `(`)
f.WriteLine(ParameterList(parametersType) + `) (`)
if method.ResponsesTypeName == "" {
f.WriteLine(`err error,`)
} else {
f.WriteLine(`response *` + method.ResponsesTypeName + `,`)
f.WriteLine(`err error,`)
}
f.WriteLine(` ) {`)
path := method.Path
path = strings.Replace(path, "{+", "{", -1)
f.WriteLine(`path := client.service + "` + path + `"`)
if parametersType != nil {
if parametersType.HasFieldWithPosition(surface.Position_PATH) {
for _, field := range parametersType.Fields {
if field.Position == surface.Position_PATH {
f.WriteLine(`path = strings.Replace(path, "{` + field.Name + `}", fmt.Sprintf("%v", ` +
field.ParameterName + `), 1)`)
}
}
}
if parametersType.HasFieldWithPosition(surface.Position_QUERY) {
f.WriteLine(`v := url.Values{}`)
for _, field := range parametersType.Fields {
if field.Position == surface.Position_QUERY {
if field.NativeType == "string" {
f.WriteLine(`if (` + field.ParameterName + ` != "") {`)
f.WriteLine(` v.Set("` + field.Name + `", ` + field.ParameterName + `)`)
f.WriteLine(`}`)
}
}
}
f.WriteLine(`if client.APIKey != "" {`)
f.WriteLine(` v.Set("key", client.APIKey)`)
f.WriteLine(`}`)
f.WriteLine(`if len(v) > 0 {`)
f.WriteLine(` path = path + "?" + v.Encode()`)
f.WriteLine(`}`)
}
}
if method.Method == "POST" {
f.WriteLine(`body := new(bytes.Buffer)`)
f.WriteLine(`json.NewEncoder(body).Encode(` + parametersType.FieldWithPosition(surface.Position_BODY).Name + `)`)
f.WriteLine(`req, err := http.NewRequest("` + method.Method + `", path, body)`)
f.WriteLine(`reqHeaders := make(http.Header)`)
f.WriteLine(`reqHeaders.Set("Content-Type", "application/json")`)
f.WriteLine(`req.Header = reqHeaders`)
} else {
f.WriteLine(`req, err := http.NewRequest("` + method.Method + `", path, nil)`)
}
f.WriteLine(`if err != nil {return}`)
f.WriteLine(`resp, err := client.client.Do(req)`)
f.WriteLine(`if err != nil {return}`)
f.WriteLine(`defer resp.Body.Close()`)
f.WriteLine(`if resp.StatusCode != 200 {`)
if responsesType != nil {
f.WriteLine(` return nil, errors.New(resp.Status)`)
} else {
f.WriteLine(` return errors.New(resp.Status)`)
}
f.WriteLine(`}`)
if responsesType != nil {
f.WriteLine(`response = &` + responsesType.Name + `{}`)
f.WriteLine(`switch {`)
// first handle everything that isn't "default"
for _, responseField := range responsesType.Fields {
if responseField.Name != "default" {
f.WriteLine(`case resp.StatusCode == ` + responseField.Name + `:`)
f.WriteLine(` body, err := ioutil.ReadAll(resp.Body)`)
f.WriteLine(` if err != nil {return nil, err}`)
f.WriteLine(` result := &` + responseField.NativeType + `{}`)
f.WriteLine(` err = json.Unmarshal(body, result)`)
f.WriteLine(` if err != nil {return nil, err}`)
f.WriteLine(` response.` + responseField.FieldName + ` = result`)
}
}
// then handle "default"
hasDefault := false
for _, responseField := range responsesType.Fields {
if responseField.Name == "default" {
hasDefault = true
f.WriteLine(`default:`)
f.WriteLine(` defer resp.Body.Close()`)
f.WriteLine(` body, err := ioutil.ReadAll(resp.Body)`)
f.WriteLine(` if err != nil {return nil, err}`)
f.WriteLine(` result := &` + responseField.NativeType + `{}`)
f.WriteLine(` err = json.Unmarshal(body, result)`)
f.WriteLine(` if err != nil {return nil, err}`)
f.WriteLine(` response.` + responseField.FieldName + ` = result`)
}
}
if !hasDefault {
f.WriteLine(`default:`)
f.WriteLine(` break`)
}
f.WriteLine(`}`) // close switch statement
}
f.WriteLine("return")
f.WriteLine("}")
}
return f.Bytes(), nil
}

View File

@ -1,30 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
func (renderer *Renderer) RenderConstants() ([]byte, error) {
f := NewLineWriter()
f.WriteLine("// GENERATED FILE: DO NOT EDIT!")
f.WriteLine(``)
f.WriteLine("package " + renderer.Package)
f.WriteLine(``)
f.WriteLine(`// ServicePath is the base URL of the service.`)
f.WriteLine(`const ServicePath = "` + `"`)
f.WriteLine(``)
f.WriteLine(`// OAuthScopes lists the OAuth scopes required by the service.`)
f.WriteLine(`const OAuthScopes = "` + `"`)
return f.Bytes(), nil
}

View File

@ -1,64 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"strings"
)
func (renderer *Renderer) RenderProvider() ([]byte, error) {
f := NewLineWriter()
f.WriteLine("// GENERATED FILE: DO NOT EDIT!\n")
f.WriteLine("package " + renderer.Package)
f.WriteLine(``)
f.WriteLine(`// To create a server, first write a class that implements this interface.`)
f.WriteLine(`// Then pass an instance of it to Initialize().`)
f.WriteLine(`type Provider interface {`)
for _, method := range renderer.Model.Methods {
parametersType := renderer.Model.TypeWithTypeName(method.ParametersTypeName)
responsesType := renderer.Model.TypeWithTypeName(method.ResponsesTypeName)
f.WriteLine(``)
f.WriteLine(commentForText(method.Description))
if parametersType != nil {
if responsesType != nil {
f.WriteLine(method.ProcessorName +
`(parameters *` + parametersType.Name +
`, responses *` + responsesType.Name + `) (err error)`)
} else {
f.WriteLine(method.ProcessorName + `(parameters *` + parametersType.Name + `) (err error)`)
}
} else {
if responsesType != nil {
f.WriteLine(method.ProcessorName + `(responses *` + responsesType.Name + `) (err error)`)
} else {
f.WriteLine(method.ProcessorName + `() (err error)`)
}
}
}
f.WriteLine(`}`)
return f.Bytes(), nil
}
func commentForText(text string) string {
result := ""
lines := strings.Split(text, "\n")
for i, line := range lines {
if i > 0 {
result += "\n"
}
result += "// " + line
}
return result
}

View File

@ -1,168 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
surface "github.com/googleapis/gnostic/surface"
)
func (renderer *Renderer) RenderServer() ([]byte, error) {
f := NewLineWriter()
f.WriteLine("// GENERATED FILE: DO NOT EDIT!")
f.WriteLine(``)
f.WriteLine("package " + renderer.Package)
f.WriteLine(``)
imports := []string{
"github.com/gorilla/mux",
"net/http",
}
f.WriteLine(``)
f.WriteLine(`import (`)
for _, imp := range imports {
f.WriteLine(`"` + imp + `"`)
}
f.WriteLine(`)`)
f.WriteLine(`func intValue(s string) (v int64) {`)
f.WriteLine(` v, _ = strconv.ParseInt(s, 10, 64)`)
f.WriteLine(` return v`)
f.WriteLine(`}`)
f.WriteLine(``)
f.WriteLine(`// This package-global variable holds the user-written Provider for API services.`)
f.WriteLine(`// See the Provider interface for details.`)
f.WriteLine(`var provider Provider`)
f.WriteLine(``)
f.WriteLine(`// These handlers serve API methods.`)
f.WriteLine(``)
for _, method := range renderer.Model.Methods {
parametersType := renderer.Model.TypeWithTypeName(method.ParametersTypeName)
responsesType := renderer.Model.TypeWithTypeName(method.ResponsesTypeName)
f.WriteLine(`// Handler`)
f.WriteLine(commentForText(method.Description))
f.WriteLine(`func ` + method.HandlerName + `(w http.ResponseWriter, r *http.Request) {`)
f.WriteLine(` var err error`)
if parametersType != nil {
f.WriteLine(`// instantiate the parameters structure`)
f.WriteLine(`parameters := &` + parametersType.Name + `{}`)
if method.Method == "POST" {
f.WriteLine(`// deserialize request from post data`)
f.WriteLine(`decoder := json.NewDecoder(r.Body)`)
f.WriteLine(`err = decoder.Decode(&parameters.` +
parametersType.FieldWithPosition(surface.Position_BODY).FieldName + `)`)
f.WriteLine(`if err != nil {`)
f.WriteLine(` w.WriteHeader(http.StatusBadRequest)`)
f.WriteLine(` w.Write([]byte(err.Error() + "\n"))`)
f.WriteLine(` return`)
f.WriteLine(`}`)
}
f.WriteLine(`// get request fields in path and query parameters`)
if parametersType.HasFieldWithPosition(surface.Position_PATH) {
f.WriteLine(`vars := mux.Vars(r)`)
}
if parametersType.HasFieldWithPosition(surface.Position_FORMDATA) {
f.WriteLine(`r.ParseForm()`)
}
for _, field := range parametersType.Fields {
if field.Position == surface.Position_PATH {
if field.Type == "string" {
f.WriteLine(fmt.Sprintf("// %+v", field))
f.WriteLine(`if value, ok := vars["` + field.Name + `"]; ok {`)
f.WriteLine(` parameters.` + field.FieldName + ` = value`)
f.WriteLine(`}`)
} else {
f.WriteLine(`if value, ok := vars["` + field.Name + `"]; ok {`)
f.WriteLine(` parameters.` + field.FieldName + ` = intValue(value)`)
f.WriteLine(`}`)
}
} else if field.Position == surface.Position_FORMDATA {
f.WriteLine(`if len(r.Form["` + field.Name + `"]) > 0 {`)
f.WriteLine(` parameters.` + field.FieldName + ` = intValue(r.Form["` + field.Name + `"][0])`)
f.WriteLine(`}`)
}
}
}
if responsesType != nil {
f.WriteLine(`// instantiate the responses structure`)
f.WriteLine(`responses := &` + method.ResponsesTypeName + `{}`)
}
f.WriteLine(`// call the service provider`)
callLine := `err = provider.` + method.ProcessorName
if parametersType != nil {
if responsesType != nil {
callLine += `(parameters, responses)`
} else {
callLine += `(parameters)`
}
} else {
if responsesType != nil {
callLine += `(responses)`
} else {
callLine += `()`
}
}
f.WriteLine(callLine)
f.WriteLine(`if err == nil {`)
if responsesType != nil {
if responsesType.HasFieldWithName("OK") {
f.WriteLine(`if responses.OK != nil {`)
f.WriteLine(` // write the normal response`)
f.WriteLine(` encoder := json.NewEncoder(w)`)
f.WriteLine(` encoder.Encode(responses.OK)`)
f.WriteLine(` return`)
f.WriteLine(`}`)
}
if responsesType.HasFieldWithName("Default") {
f.WriteLine(`if responses.Default != nil {`)
f.WriteLine(` // write the error response`)
if responsesType.FieldWithName("Default").ServiceType(renderer.Model).FieldWithName("Code") != nil {
f.WriteLine(` w.WriteHeader(int(responses.Default.Code))`)
}
f.WriteLine(` encoder := json.NewEncoder(w)`)
f.WriteLine(` encoder.Encode(responses.Default)`)
f.WriteLine(` return`)
f.WriteLine(`}`)
}
}
f.WriteLine(`} else {`)
f.WriteLine(` w.WriteHeader(http.StatusInternalServerError)`)
f.WriteLine(` w.Write([]byte(err.Error() + "\n"))`)
f.WriteLine(` return`)
f.WriteLine(`}`)
f.WriteLine(`}`)
f.WriteLine(``)
}
f.WriteLine(`// Initialize the API service.`)
f.WriteLine(`func Initialize(p Provider) {`)
f.WriteLine(` provider = p`)
f.WriteLine(` var router = mux.NewRouter()`)
for _, method := range renderer.Model.Methods {
f.WriteLine(`router.HandleFunc("` + method.Path + `", ` + method.HandlerName + `).Methods("` + method.Method + `")`)
}
f.WriteLine(` http.Handle("/", router)`)
f.WriteLine(`}`)
f.WriteLine(``)
f.WriteLine(`// Provide the API service over HTTP.`)
f.WriteLine(`func ServeHTTP(address string) error {`)
f.WriteLine(` if provider == nil {`)
f.WriteLine(` return errors.New("Use ` + renderer.Package + `.Initialize() to set a service provider.")`)
f.WriteLine(` }`)
f.WriteLine(` return http.ListenAndServe(address, nil)`)
f.WriteLine(`}`)
return f.Bytes(), nil
}

View File

@ -1,57 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
surface "github.com/googleapis/gnostic/surface"
)
func (renderer *Renderer) RenderTypes() ([]byte, error) {
f := NewLineWriter()
f.WriteLine(`// GENERATED FILE: DO NOT EDIT!`)
f.WriteLine(``)
f.WriteLine(`package ` + renderer.Package)
f.WriteLine(`// Types used by the API.`)
for _, modelType := range renderer.Model.Types {
f.WriteLine(`// ` + modelType.Description)
if modelType.Kind == surface.TypeKind_STRUCT {
f.WriteLine(`type ` + modelType.TypeName + ` struct {`)
for _, field := range modelType.Fields {
prefix := ""
if field.Kind == surface.FieldKind_REFERENCE {
prefix = "*"
} else if field.Kind == surface.FieldKind_ARRAY {
prefix = "[]"
} else if field.Kind == surface.FieldKind_MAP {
prefix = "map[string]"
}
f.WriteLine(field.FieldName + ` ` + prefix + field.NativeType + jsonTag(field))
}
f.WriteLine(`}`)
} else if modelType.Kind == surface.TypeKind_OBJECT {
f.WriteLine(`type ` + modelType.TypeName + ` map[string]` + modelType.ContentType)
} else {
f.WriteLine(`type ` + modelType.TypeName + ` struct {}`)
}
}
return f.Bytes(), nil
}
func jsonTag(field *surface.Field) string {
if field.Serialize {
return " `json:" + `"` + field.Name + `,omitempty"` + "`"
}
return ""
}

View File

@ -1,67 +0,0 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
_ "os"
"path/filepath"
plugins "github.com/googleapis/gnostic/plugins"
surface "github.com/googleapis/gnostic/surface"
)
// Renderer generates code for a surface.Model.
type Renderer struct {
Model *surface.Model
Package string // package name
}
// NewServiceRenderer creates a renderer.
func NewServiceRenderer(model *surface.Model) (renderer *Renderer, err error) {
renderer = &Renderer{}
renderer.Model = model
return renderer, nil
}
// Generate runs the renderer to generate the named files.
func (renderer *Renderer) Render(response *plugins.Response, files []string) (err error) {
for _, filename := range files {
file := &plugins.File{Name: filename}
switch filename {
case "client.go":
file.Data, err = renderer.RenderClient()
case "types.go":
file.Data, err = renderer.RenderTypes()
case "provider.go":
file.Data, err = renderer.RenderProvider()
case "server.go":
file.Data, err = renderer.RenderServer()
case "constants.go":
file.Data, err = renderer.RenderConstants()
default:
file.Data = nil
}
if err != nil {
response.Errors = append(response.Errors, fmt.Sprintf("ERROR %v", err))
}
// run generated Go files through goimports
if filepath.Ext(file.Name) == ".go" {
file.Data, err = goimports(file.Name, file.Data)
}
response.Files = append(response.Files, file)
}
return
}