├── alpaca
├── format_blueprint.go
├── error.go
├── template.go
├── langs_node.go
├── langs_python.go
├── langs_ruby.go
├── langs_php.go
├── library.go
├── alpaca.go
├── utils_test.go
└── utils.go
├── templates
├── php
│ ├── gitignore
│ ├── lib
│ │ ├── Exception
│ │ │ ├── ExceptionInterface.php
│ │ │ └── ClientException.php
│ │ ├── HttpClient
│ │ │ ├── Response.php
│ │ │ ├── ResponseHandler.php
│ │ │ ├── RequestHandler.php
│ │ │ ├── ErrorHandler.php
│ │ │ ├── AuthHandler.php
│ │ │ └── HttpClient.php
│ │ ├── Client.php
│ │ └── Api
│ │ │ └── Api.php
│ ├── composer.json
│ └── readme.md
├── node
│ ├── gitignore
│ ├── lib
│ │ ├── error
│ │ │ ├── index.js
│ │ │ └── client_error.js
│ │ ├── http_client
│ │ │ ├── response.js
│ │ │ ├── response_handler.js
│ │ │ ├── request_handler.js
│ │ │ ├── error_handler.js
│ │ │ ├── auth_handler.js
│ │ │ └── index.js
│ │ ├── index.js
│ │ ├── client.js
│ │ └── api
│ │ │ └── api.js
│ ├── package.json
│ └── readme.md
├── python
│ ├── lib
│ │ ├── __init__.py
│ │ ├── error
│ │ │ ├── __init__.py
│ │ │ └── client_error.py
│ │ ├── api
│ │ │ ├── __init__.py
│ │ │ └── api.py
│ │ ├── http_client
│ │ │ ├── response.py
│ │ │ ├── response_handler.py
│ │ │ ├── error_handler.py
│ │ │ ├── request_handler.py
│ │ │ ├── auth_handler.py
│ │ │ └── __init__.py
│ │ └── client.py
│ ├── gitignore
│ ├── setup.py
│ └── readme.md
└── ruby
│ ├── lib
│ ├── version.rb
│ ├── error.rb
│ ├── name.rb
│ ├── error
│ │ └── client_error.rb
│ ├── http_client
│ │ ├── response.rb
│ │ ├── response_handler.rb
│ │ ├── request_handler.rb
│ │ ├── error_handler.rb
│ │ └── auth_handler.rb
│ ├── client.rb
│ ├── api
│ │ └── api.rb
│ └── http_client.rb
│ ├── gitignore
│ ├── gemspec
│ └── readme.md
├── .travis.yml
├── .gitignore
├── Godeps
├── examples
├── buffer
│ ├── pkg.json
│ ├── api.json
│ └── doc.json
└── helpful
│ ├── pkg.json
│ ├── api.json
│ └── doc.json
├── CHANGELOG.md
├── main.go
├── Makefile
├── README.md
└── LICENSE
/alpaca/format_blueprint.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
--------------------------------------------------------------------------------
/templates/php/gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | composer.lock
3 |
--------------------------------------------------------------------------------
/templates/node/gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 |
--------------------------------------------------------------------------------
/templates/python/lib/__init__.py:
--------------------------------------------------------------------------------
1 | from .client import Client
2 |
--------------------------------------------------------------------------------
/templates/python/lib/error/__init__.py:
--------------------------------------------------------------------------------
1 | from .client_error import ClientError
2 |
--------------------------------------------------------------------------------
/templates/ruby/lib/version.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 | VERSION = "{{.Pkg.Version}}"
3 | end
4 |
--------------------------------------------------------------------------------
/templates/node/lib/error/index.js:
--------------------------------------------------------------------------------
1 | var error = module.exports;
2 |
3 | error.ClientError = require('./client_error');
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 |
3 | go:
4 | - 1.9.x
5 | - 1.10.x
6 | - 1.11.x
7 |
8 | install: make
9 | script: make test
10 |
--------------------------------------------------------------------------------
/templates/php/lib/Exception/ExceptionInterface.php:
--------------------------------------------------------------------------------
1 | body = $body;
12 | $this->code = $code;
13 | $this->headers = $headers;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client/response.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 |
3 | module HttpClient
4 |
5 | # Response object contains the response returned by the client
6 | class Response
7 |
8 | attr_accessor :body, :code, :headers
9 |
10 | def initialize(body, code, headers)
11 | @body = body
12 | @code = code
13 | @headers = headers
14 | end
15 |
16 | end
17 |
18 | end
19 |
20 | end
21 |
--------------------------------------------------------------------------------
/templates/node/lib/index.js:
--------------------------------------------------------------------------------
1 | var Client = require('./{{call .Fnc.underscore .Pkg.Name}}/client');
2 |
3 | // Export module
4 | var {{call .Fnc.camelizeDownFirst .Pkg.Name}} = module.exports;
5 |
6 | /**
7 | * This file contains the global namespace for the module
8 | */
9 | {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client = function({{if .Api.BaseAsArg}}baseUrl, {{end}}auth, options) {
10 | return new Client({{if .Api.BaseAsArg}}baseUrl, {{end}}auth, options);
11 | };
12 |
--------------------------------------------------------------------------------
/templates/php/lib/Exception/ClientException.php:
--------------------------------------------------------------------------------
1 | code = $code;
15 | parent::__construct($message);
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/templates/python/lib/http_client/response_handler.py:
--------------------------------------------------------------------------------
1 | class ResponseHandler(object):
2 |
3 | """ResponseHandler takes care of decoding the response body into suitable type"""
4 |
5 | @staticmethod
6 | def get_body(response):
7 | typ = response.headers.get('content-type', '')
8 | body = response.text
9 | {{if .Api.Response.Formats.Json}}
10 | # Response body is in JSON
11 | if typ.find('json') != -1:
12 | body = response.json()
13 | {{end}}
14 | return body
15 |
--------------------------------------------------------------------------------
/examples/buffer/pkg.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Buffer",
3 | "package": "buffer-alpaca",
4 | "version": "0.1.0",
5 | "url": "https://bufferapp.com",
6 | "keywords": ["alpaca", "buffer", "api", "client", "library"],
7 | "official": false,
8 | "author": {
9 | "name": "Pavan Kumar Sunkara",
10 | "email": "pavan.sss1991@gmail.com",
11 | "url": "http://github.com/pksunkara"
12 | },
13 | "git": {
14 | "site": "github.com",
15 | "user": "alpaca-api",
16 | "name": "buffer"
17 | },
18 | "license": "MIT",
19 | "php": {
20 | "vendor": "pksunkara"
21 | },
22 | "python": {
23 | "license": "MIT License"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/templates/node/lib/http_client/response_handler.js:
--------------------------------------------------------------------------------
1 | var response = module.exports;
2 |
3 | /**
4 | * This module takes care of decoding the response body into suitable type
5 | */
6 | response.getBody = function(res, body, callback) {
7 | var type = res.headers['content-type'], error = null;
8 | {{if .Api.Response.Formats.Json}}
9 | // Response body is in JSON
10 | if (type.indexOf('json') !== -1 && typeof(body) !== 'object') {
11 | try {
12 | body = JSON.parse(body || '{}');
13 | } catch (err) {
14 | error = err;
15 | }
16 | }
17 | {{end}}
18 | return callback(error, res, body);
19 | };
20 |
--------------------------------------------------------------------------------
/examples/helpful/pkg.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Helpful",
3 | "package": "helpful-client",
4 | "version": "1.0.0",
5 | "url": "https://helpful.io",
6 | "keywords": ["alpaca", "helpful", "assemblymade", "api", "client", "library"],
7 | "official": true,
8 | "author": {
9 | "name": "Pavan Kumar Sunkara",
10 | "email": "pavan.sss1991@gmail.com",
11 | "url": "http://assemblymade.com/helpful"
12 | },
13 | "git": {
14 | "site": "github.com",
15 | "user": "asm-helpful",
16 | "name": "helpful"
17 | },
18 | "license": "MIT",
19 | "php": {
20 | "vendor": "helpful"
21 | },
22 | "python": {
23 | "license": "MIT License"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/templates/ruby/gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 |
3 | Gem::Specification.new do |gem|
4 | gem.name = "{{.Pkg.Package}}"
5 | gem.version = "{{.Pkg.Version}}"
6 | gem.description = "{{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for ruby"
7 | gem.summary = "{{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for ruby"
8 |
9 | gem.author = "{{.Pkg.Author.Name}}"
10 | gem.email = "{{.Pkg.Author.Email}}"
11 | gem.homepage = "{{.Pkg.Url}}"
12 | gem.license = "{{.Pkg.License}}"
13 |
14 | gem.require_paths = ['lib']
15 |
16 | gem.files = Dir["lib/**/*"]
17 |
18 | gem.add_dependency "faraday", "~> 0.9", ">= 0.9.0"
19 | gem.add_dependency "json", "~> 1.7", ">= 1.7.7"
20 | end
21 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client/response_handler.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 |
3 | module HttpClient
4 |
5 | # ResponseHandler takes care of decoding the response body into suitable type
6 | class ResponseHandler
7 |
8 | def self.get_body(response)
9 | type = response.headers["content-type"]
10 | body = response.body
11 | {{if .Api.Response.Formats.Json}}
12 | # Response body is in JSON
13 | if type and type.include?("json")
14 | begin
15 | body = JSON.parse body
16 | rescue JSON::ParserError
17 | return body
18 | end
19 | end
20 | {{end}}
21 | return body
22 | end
23 |
24 | end
25 |
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/templates/php/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{.Pkg.Php.Vendor}}/{{.Pkg.Package}}",
3 | "version": "{{.Pkg.Version}}",
4 | "description": "{{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for PHP",
5 | "homepage": "{{.Pkg.Url}}",
6 | "authors": [
7 | {
8 | "name": "{{.Pkg.Author.Name}}",
9 | "email": "{{.Pkg.Author.Email}}",
10 | "homepage": "{{.Pkg.Author.Url}}"
11 | }
12 | ],
13 | "keywords": ["{{call .Fnc.join .Pkg.Keywords "\", \""}}"],
14 | "autoload": {
15 | "psr-0": {
16 | "{{.Pkg.Name}}\\": "lib/"
17 | }
18 | },
19 | "require": {
20 | "ext-json": "*",
21 | "guzzlehttp/guzzle": "3.7.*"
22 | },
23 | "support": {
24 | "issues": "https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-php/issues"
25 | },
26 | "license": "{{.Pkg.License}}"
27 | }
28 |
--------------------------------------------------------------------------------
/templates/php/lib/HttpClient/ResponseHandler.php:
--------------------------------------------------------------------------------
1 | getBody(true);
15 | {{if .Api.Response.Formats.Json}}
16 | // Response body is in JSON
17 | if ($response->isContentType('json')) {
18 | $tmp = json_decode($body, true);
19 |
20 | if (JSON_ERROR_NONE === json_last_error()) {
21 | $body = $tmp;
22 | }
23 | }
24 | {{end}}
25 | return $body;
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/templates/node/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{.Pkg.Package}}",
3 | "version": "{{.Pkg.Version}}",
4 | "description": "{{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for node.js",
5 | "author": "{{.Pkg.Author.Name}} <{{.Pkg.Author.Email}}> ({{.Pkg.Author.Url}})",
6 | "homepage": "{{.Pkg.Url}}",
7 | "keywords": ["{{call .Fnc.join .Pkg.Keywords "\", \""}}"],
8 | "repository": {
9 | "type": "git",
10 | "url": "https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-node"
11 | },
12 | "main": "./lib/index.js",
13 | "dependencies": {
14 | "request": "2.x.x"
15 | },
16 | "bugs": {
17 | "url": "https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-node/issues"
18 | },
19 | "license": "{{.Pkg.License}}",
20 | "engines": {
21 | "node": ">= 0.8.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/alpaca/template.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "github.com/GeertJohan/go.rice"
5 | "os"
6 | "path"
7 | "text/template"
8 | )
9 |
10 | func ReadTemplate(name string) *template.Template {
11 | templateBox := rice.MustFindBox("../templates")
12 |
13 | temp, err := templateBox.String(name)
14 | HandleError(err)
15 |
16 | return template.Must(template.New(name).Parse(temp))
17 | }
18 |
19 | func WriteTemplate(temp *template.Template, out string, data interface{}) {
20 | file, err := os.Create(path.Clean(out))
21 | defer file.Close()
22 | HandleError(err)
23 |
24 | HandleError(temp.Execute(file, data))
25 | }
26 |
27 | func ChooseTemplate(template string) func(string, string, interface{}) {
28 | return func(name string, out string, data interface{}) {
29 | temp := ReadTemplate(path.Join(template, name))
30 | WriteTemplate(temp, out, data)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/templates/node/lib/client.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Main client for the module
3 | */
4 | var Client = function({{if .Api.BaseAsArg}}baseUrl, {{end}}auth, options) {
5 | this.httpClient = new (require('./http_client').HttpClient)({{if .Api.BaseAsArg}}baseUrl, {{end}}auth, options);
6 |
7 | return this;
8 | };
9 | {{with $data := .}}{{range .Api.Classes}}
10 | /**
11 | * {{(index $data.Doc .Name).Desc}}{{with .Args}}
12 | *{{end}}{{with $class := .}}{{range .Args}}
13 | * @param "{{.}}" {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}{{end}}
14 | */
15 | Client.prototype.{{call $data.Fnc.camelizeDownFirst .Name}} = function ({{call $data.Fnc.args.node .Args true}}) {
16 | return new (require('./api/{{call $data.Fnc.underscore .Name}}'))({{call $data.Fnc.args.node .Args}}this.httpClient);
17 | };
18 | {{end}}{{end}}
19 | // Export module
20 | module.exports = Client;
21 |
--------------------------------------------------------------------------------
/templates/node/lib/http_client/request_handler.js:
--------------------------------------------------------------------------------
1 | var request = module.exports;
2 |
3 | /**
4 | * This module takes care of encoding the request body into format given by options
5 | */
6 | request.setBody = function(reqobj, body, options) {
7 | var type = (options.request_type ? options.request_type : '{{or .Api.Request.Formats.Default "raw"}}');
8 |
9 | {{if .Api.Request.Formats.Json}}
10 | // Encoding body into JSON format
11 | if (type === 'json') {
12 | reqobj.json = body;
13 | }
14 | {{end}}{{if .Api.Request.Formats.Form}}
15 | // Encoding body into form-urlencoded format
16 | if (type === 'form') {
17 | reqobj.form = body;
18 | }
19 | {{end}}
20 | // Raw body
21 | if (type === 'raw') {
22 | reqobj.body = body;
23 |
24 | if (typeof reqobj.body === 'object') {
25 | delete reqobj.body;
26 | }
27 | }
28 |
29 | return reqobj;
30 | };
31 |
--------------------------------------------------------------------------------
/templates/python/lib/client.py:
--------------------------------------------------------------------------------
1 | from .http_client import HttpClient
2 |
3 | # Assign all the api classes{{with $data := .}}{{range .Api.Classes}}
4 | from .api.{{call $data.Fnc.underscore .Name}} import {{call $data.Fnc.camelize .Name}}{{end}}{{end}}
5 |
6 |
7 | class Client(object):
8 |
9 | def __init__(self, {{if .Api.BaseAsArg}}base_url, {{end}}auth={}, options={}):
10 | self.http_client = HttpClient({{if .Api.BaseAsArg}}base_url, {{end}}auth, options)
11 | {{with $data := .}}{{range .Api.Classes}}
12 | def {{call $data.Fnc.underscore .Name}}(self{{call $data.Fnc.args.python .Args true true}}):
13 | """{{(index $data.Doc .Name).Desc}}{{with .Args}}
14 |
15 | Args:{{end}}{{with $class := .}}{{range .Args}}
16 | {{.}}: {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}{{end}}
17 | """
18 | return {{call $data.Fnc.camelize .Name}}({{call $data.Fnc.args.python .Args}}self.http_client)
19 | {{end}}{{end}}
20 |
--------------------------------------------------------------------------------
/templates/php/lib/Client.php:
--------------------------------------------------------------------------------
1 | httpClient = new HttpClient({{if .Api.BaseAsArg}}$baseUrl, {{end}}$auth, $options);
14 | }
15 | {{with $data := .}}{{range .Api.Classes}}
16 | /**
17 | * {{(index $data.Doc .Name).Desc}}{{with .Args}}
18 | *{{end}}{{with $class := .}}{{range .Args}}
19 | * @param ${{.}} {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}{{end}}
20 | */
21 | public function {{call $data.Fnc.camelizeDownFirst .Name}}({{call $data.Fnc.args.php .Args true}})
22 | {
23 | return new Api\{{call $data.Fnc.camelize .Name}}({{call $data.Fnc.args.php .Args}}$this->httpClient);
24 | }
25 | {{end}}{{end}}
26 | }
27 |
--------------------------------------------------------------------------------
/templates/ruby/lib/client.rb:
--------------------------------------------------------------------------------
1 | require "faraday"
2 | require "json"
3 | {{with $data := .}}{{range .Api.Classes}}
4 | require "{{call $data.Fnc.underscore $data.Pkg.Name}}/api/{{call $data.Fnc.underscore .Name}}"{{end}}{{end}}
5 |
6 | module {{call .Fnc.camelize .Pkg.Name}}
7 |
8 | class Client
9 |
10 | def initialize({{if .Api.BaseAsArg}}base_url, {{end}}auth = {}, options = {})
11 | @http_client = {{call .Fnc.camelize .Pkg.Name}}::HttpClient::HttpClient.new({{if .Api.BaseAsArg}}base_url, {{end}}auth, options)
12 | end
13 | {{with $data := .}}{{range .Api.Classes}}
14 | # {{(index $data.Doc .Name).Desc}}{{with .Args}}
15 | #{{end}}{{with $class := .}}{{range .Args}}
16 | # {{.}} - {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}{{end}}
17 | def {{call $data.Fnc.underscore .Name}}({{call $data.Fnc.args.ruby .Args true}})
18 | {{call $data.Fnc.camelize $data.Pkg.Name}}::Api::{{call $data.Fnc.camelize .Name}}.new({{call $data.Fnc.args.ruby .Args}}@http_client)
19 | end
20 | {{end}}{{end}}
21 | end
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 0.2.1
2 |
3 | Using Mozilla 2.0 license from now on.
4 |
5 | Features:
6 |
7 | - Support `authorization.header_prefix` for authorization headers (#6)
8 | - Can now make authentication compulsory using `authorizaiton.need_auth`
9 | - Default value is `false` for `response.formats.html`
10 | - Default value is `false` for `request.formats.form`
11 | - Allow API `base_url` to be an argument (#30)
12 | - Parameters needed for method URL can be defined in the method
13 |
14 | Bugfixes:
15 |
16 | - Helpful error when missing language specific fields in `pkg.json`
17 | - Better building of binary (#22)
18 | - Python style fixes (#26)
19 | - Comments in generated code are now params/args aware
20 | - Fix bug with JSON parsing response in node.js
21 | - Ruby style fixes
22 |
23 | ## 0.2.0
24 |
25 | Features:
26 |
27 | - Added Makefile (#7)
28 | - Added support for `no_verify_ssl` in **api.json** (#10)
29 | - Made `params` in **api.json** into an array of hashes (#12)
30 |
31 | Bugfixes:
32 |
33 | - MakeStringArrayInterface and ArrayStringInterface supports nil (#14)
34 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "fmt"
5 | "github.com/jessevdk/go-flags"
6 | "github.com/pksunkara/alpaca/alpaca"
7 | "os"
8 | )
9 |
10 | func main() {
11 |
12 | // Options for flags package
13 | var opts struct {
14 | Version bool `short:"v" long:"version" description:"Show version information"`
15 |
16 | Format string `short:"f" long:"format" description:"API description format" value-name:"FORMAT"`
17 |
18 | Langs alpaca.LanguageOptions `group:"Language Options"`
19 | }
20 |
21 | // Build the parser
22 | parser := flags.NewParser(&opts, flags.Default)
23 |
24 | // Set usage string
25 | parser.Usage = "[options]
"
26 |
27 | // Parse the arguments
28 | args, err := parser.Parse()
29 |
30 | if err != nil {
31 | os.Exit(0)
32 | }
33 |
34 | // Print version and exit
35 | if opts.Version {
36 | fmt.Println(alpaca.Version)
37 | os.Exit(0)
38 | }
39 |
40 | // If no argument is given
41 | if len(args) == 0 {
42 | parser.WriteHelp(os.Stdout)
43 | os.Exit(0)
44 | }
45 |
46 | alpaca.LoadLibraryPath(args[0])
47 |
48 | if opts.Format != "" {
49 | alpaca.ConvertFormat(opts.Format)
50 | }
51 |
52 | alpaca.WriteLibraries(&opts.Langs)
53 | }
54 |
--------------------------------------------------------------------------------
/templates/php/lib/HttpClient/RequestHandler.php:
--------------------------------------------------------------------------------
1 | setBody($body, 'application/json');
21 | }
22 | {{end}}{{if .Api.Request.Formats.Form}}
23 | if ($type == 'form') {
24 | // Encoding body into form-urlencoded format
25 | return $request->addPostFields($body);
26 | }
27 | {{end}}
28 | if ($type == 'raw') {
29 | // Raw body
30 | return $request->setBody($body, $header);
31 | }
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client/request_handler.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 |
3 | module HttpClient
4 |
5 | # RequestHandler takes care of encoding the request body into format given by options
6 | class RequestHandler
7 |
8 | def self.set_body(options)
9 | type = options.fetch(:request_type, "{{or .Api.Request.Formats.Default "raw"}}")
10 | {{if .Api.Request.Formats.Json}}
11 | # Encoding request body into JSON format
12 | if type == "json"
13 | options[:body] = options[:body].to_json
14 | options[:headers]["content-type"] = "application/json"
15 | end
16 | {{end}}{{if .Api.Request.Formats.Form}}
17 | # Encoding body into form-urlencoded format
18 | if type == "form"
19 | options[:body] = Faraday::Utils::ParamsHash[options[:body]].to_query
20 | options[:headers]["content-type"] = "application/x-www-form-urlencoded"
21 | end
22 | {{end}}
23 | # Raw body
24 | if type == "raw"
25 | options[:body] = options[:body].is_a?(Hash) ? "" : options[:body]
26 | options[:headers].delete("content-type")
27 | end
28 |
29 | return options
30 | end
31 |
32 | end
33 |
34 | end
35 |
36 | end
37 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | VERSION = 0.2.1
2 |
3 | GO_RICE = rice
4 | GO_FMT = gofmt -w
5 | GO_XC = goxc
6 |
7 | GOXC_FILE = .goxc.local.json
8 |
9 | DEPS = \
10 | github.com/GeertJohan/go.rice/rice \
11 | github.com/robertkrimen/terst \
12 | github.com/jessevdk/go-flags \
13 | github.com/kardianos/osext \
14 | bitbucket.org/pkg/inflect
15 |
16 | all:deps templates
17 |
18 | templates:clean
19 | $(GO_RICE) --import-path github.com/pksunkara/alpaca/alpaca embed
20 |
21 | compile:templates goxc
22 |
23 | goxc:
24 | $(shell echo '{\n "ArtifactsDest": "build",\n "ConfigVersion": "0.9",' > $(GOXC_FILE))
25 | $(shell echo ' "PackageVersion": "$(VERSION)",\n "TaskSettings": {' >> $(GOXC_FILE))
26 | $(shell echo ' "bintray": {\n "apikey": "",\n "package": "alpaca",' >> $(GOXC_FILE))
27 | $(shell echo ' "repository": "utils",\n "subject": "pksunkara"' >> $(GOXC_FILE))
28 | $(shell echo ' }\n }\n}' >> $(GOXC_FILE))
29 | $(GO_XC)
30 |
31 | bintray:
32 | $(GO_XC) bintray
33 |
34 | test:
35 | go test -v ./...
36 |
37 | test-cover:
38 | go test -coverprofile=coverage.out github.com/pksunkara/alpaca/alpaca
39 | go tool cover -html=coverage.out
40 |
41 | install:
42 | go install -a github.com/pksunkara/alpaca
43 |
44 | deps:
45 | go get -u $(DEPS)
46 |
47 | clean:
48 | $(GO_RICE) --import-path github.com/pksunkara/alpaca/alpaca clean
49 |
--------------------------------------------------------------------------------
/templates/node/lib/http_client/error_handler.js:
--------------------------------------------------------------------------------
1 | var errors = require('../error');
2 |
3 | /**
4 | * ErrorHanlder takes care of selecting the error message from response body
5 | */
6 | module.exports = function(response, body, callback) {
7 | var code = response.statusCode
8 | , message = ''
9 | , type = response.headers['content-type'];
10 |
11 | if (Math.floor(code/100) === 5) {
12 | return callback(new errors.ClientError('Error ' + code, code));
13 | }
14 |
15 | if (Math.floor(code/100) === 4) {
16 | // If HTML, whole body is taken
17 | if (typeof body === 'string') {
18 | message = body;
19 | }
20 | {{if .Api.Response.Formats.Json}}
21 | // If JSON, a particular field is taken and used
22 | if (type.indexOf('json') !== -1 && typeof body === 'object') {
23 | if (body['{{.Api.Error.Message}}']) {
24 | message = body['{{.Api.Error.Message}}'];
25 | } else {
26 | message = 'Unable to select error message from json returned by request responsible for error';
27 | }
28 | }
29 | {{end}}
30 | if (message === '') {
31 | message = 'Unable to understand the content type of response returned by request responsible for error';
32 | }
33 |
34 | return callback(new errors.ClientError(message, code));
35 | }
36 |
37 | return callback(null, response, body);
38 | };
39 |
--------------------------------------------------------------------------------
/templates/python/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | try:
5 | from setuptools import setup
6 | except ImportError:
7 | from distutils.core import setup
8 |
9 | setup(
10 | name='{{.Pkg.Package}}',
11 | version='{{.Pkg.Version}}',
12 | description='{{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for python',
13 | author='{{.Pkg.Author.Name}}',
14 | author_email='{{.Pkg.Author.Email}}',
15 | url='{{.Pkg.Url}}',
16 | license='{{.Pkg.License}}',
17 | install_requires=[
18 | 'requests >= 2.1.0'
19 | ],
20 | packages=[
21 | '{{call .Fnc.underscore .Pkg.Name}}',
22 | '{{call .Fnc.underscore .Pkg.Name}}.api',
23 | '{{call .Fnc.underscore .Pkg.Name}}.error',
24 | '{{call .Fnc.underscore .Pkg.Name}}.http_client'
25 | ],
26 | classifiers=[
27 | 'Development Status :: 5 - Production/Stable',
28 | 'Intended Audience :: Developers',{{if .Pkg.Python.License}}
29 | 'License :: OSI Approved :: {{.Pkg.Python.License}}',{{end}}
30 | 'Operating System :: OS Independent',
31 | 'Programming Language :: Python :: 2.6',
32 | 'Programming Language :: Python :: 2.7',
33 | 'Programming Language :: Python :: 3.2',
34 | 'Programming Language :: Python :: 3.3',
35 | 'Topic :: Software Development :: Libraries :: Python Modules',
36 | ]
37 | )
38 |
--------------------------------------------------------------------------------
/templates/python/lib/http_client/error_handler.py:
--------------------------------------------------------------------------------
1 | from ..error import ClientError
2 | from .response_handler import ResponseHandler
3 |
4 |
5 | class ErrorHandler(object):
6 |
7 | """ErrorHandler takes care of getting the error message from response body"""
8 |
9 | @staticmethod
10 | def check_error(response, *args, **kwargs):
11 | code = response.status_code
12 | typ = response.headers.get('content-type', '')
13 |
14 | if code in range(500, 600):
15 | raise ClientError('Error ' + str(code), code)
16 | elif code in range(400, 500):
17 | body = ResponseHandler.get_body(response)
18 | message = ''
19 |
20 | # If HTML, whole body is taken
21 | if isinstance(body, str):
22 | message = body
23 | {{if .Api.Response.Formats.Json}}
24 | # If JSON, a particular field is taken and used
25 | if typ.find('json') != -1 and isinstance(body, dict):
26 | if '{{.Api.Error.Message}}' in body:
27 | message = body['{{.Api.Error.Message}}']
28 | else:
29 | message = 'Unable to select error message from json returned by request responsible for error'
30 | {{end}}
31 | if message == '':
32 | message = 'Unable to understand the content type of response returned by request responsible for error'
33 |
34 | raise ClientError(message, code)
35 |
--------------------------------------------------------------------------------
/templates/ruby/lib/api/api.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 | {{define "boq"}}{{if (eq (or .Method "get") "get")}}query{{else}}body{{end}}{{end}}
3 | module Api
4 |
5 | # {{(index .Doc .Active.Name).Desc}}{{with (index .Doc .Active.Name).Args}}
6 | #{{end}}{{with $data := .}}{{range .Active.Args}}
7 | # {{.}} - {{(index ((index $data.Doc $data.Active.Name).Args) .).Desc}}{{end}}{{end}}
8 | class {{call .Fnc.camelize .Active.Name}}
9 |
10 | def initialize({{call .Fnc.args.ruby .Active.Args}}client)
11 | {{range .Active.Args}} @{{.}} = {{.}}
12 | {{end}} @client = client
13 | end
14 | {{with $data := .}}{{range .Active.Functions}}
15 | # {{(index ((index $data.Doc $data.Active.Name).Functions) .Name).Desc}}
16 | #
17 | # '{{.Path}}' {{call $data.Fnc.upper (or .Method "get")}}{{with .Params}}
18 | #{{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
19 | # {{.Name}} - {{(index ((index ((index $data.Doc $data.Active.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
20 | def {{call $data.Fnc.underscore .Name}}({{call $data.Fnc.args.ruby .Params}}options = {})
21 | body = options.fetch(:{{template "boq" .}}, {}){{range .Params}}{{if .Required}}{{if (not .UrlUse)}}
22 | body[:{{.Name}}] = {{.Name}}{{end}}{{end}}{{end}}
23 |
24 | @client.{{or .Method "get"}}("{{call $data.Fnc.path.ruby .Path $data.Active.Args .Params}}", body, options)
25 | end
26 | {{end}}{{end}}
27 | end
28 |
29 | end
30 |
31 | end
32 |
--------------------------------------------------------------------------------
/templates/python/lib/api/api.py:
--------------------------------------------------------------------------------
1 | {{define "boq"}}{{if (eq (or .Method "get") "get")}}query{{else}}body{{end}}{{end}}class {{call .Fnc.camelize .Active.Name}}(object):
2 |
3 | """{{(index .Doc .Active.Name).Desc}}{{with (index .Doc .Active.Name).Args}}
4 |
5 | Args:{{end}}{{with $data := .}}{{range .Active.Args}}
6 | {{.}}: {{(index ((index $data.Doc $data.Active.Name).Args) .).Desc}}{{end}}{{end}}
7 | """
8 |
9 | def __init__(self, {{call .Fnc.args.python .Active.Args}}client):{{range .Active.Args}}
10 | self.{{.}} = {{.}}{{end}}
11 | self.client = client
12 | {{with $data := .}}{{range .Active.Functions}}
13 | def {{call $data.Fnc.underscore .Name}}(self, {{call $data.Fnc.args.python .Params}}options={}):
14 | """{{(index ((index $data.Doc $data.Active.Name).Functions) .Name).Desc}}
15 |
16 | '{{.Path}}' {{call $data.Fnc.upper (or .Method "get")}}{{with .Params}}
17 |
18 | Args:{{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
19 | {{.Name}}: {{(index ((index ((index $data.Doc $data.Active.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
20 | """
21 | body = options['{{template "boq" .}}'] if '{{template "boq" .}}' in options else {}{{range .Params}}{{if .Required}}{{if (not .UrlUse)}}
22 | body['{{.Name}}'] = {{.Name}}{{end}}{{end}}{{end}}
23 |
24 | response = self.client.{{or .Method "get"}}('{{call $data.Fnc.path.python .Path $data.Active.Args .Params}}', body, options)
25 |
26 | return response
27 | {{end}}{{end}}
28 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client/error_handler.rb:
--------------------------------------------------------------------------------
1 | module {{call .Fnc.camelize .Pkg.Name}}
2 |
3 | module HttpClient
4 |
5 | # ErrorHanlder takes care of selecting the error message from response body
6 | class ErrorHandler < Faraday::Middleware
7 |
8 | def initialize(app)
9 | super(app)
10 | end
11 |
12 | def call(env)
13 | @app.call(env).on_complete do |env|
14 | code = env.status
15 | type = env.response_headers["content-type"]
16 |
17 | case code
18 | when 500...599
19 | raise {{call .Fnc.camelize .Pkg.Name}}::Error::ClientError.new("Error #{code}", code)
20 | when 400...499
21 | body = {{call .Fnc.camelize .Pkg.Name}}::HttpClient::ResponseHandler.get_body(env)
22 | message = ""
23 |
24 | # If HTML, whole body is taken
25 | if body.is_a?(String)
26 | message = body
27 | end
28 | {{if .Api.Response.Formats.Json}}
29 | # If JSON, a particular field is taken and used
30 | if type and type.include?("json") and body.is_a?(Hash)
31 | if body.has_key?("{{.Api.Error.Message}}")
32 | message = body["{{.Api.Error.Message}}"]
33 | else
34 | message = "Unable to select error message from json returned by request responsible for error"
35 | end
36 | end
37 | {{end}}
38 | if message == ""
39 | message = "Unable to understand the content type of response returned by request responsible for error"
40 | end
41 |
42 | raise {{call .Fnc.camelize .Pkg.Name}}::Error::ClientError.new message, code
43 | end
44 | end
45 | end
46 |
47 | end
48 |
49 | end
50 |
51 | end
52 |
--------------------------------------------------------------------------------
/templates/node/lib/api/api.js:
--------------------------------------------------------------------------------
1 | {{define "boq"}}{{if (eq (or .Method "get") "get")}}query{{else}}body{{end}}{{end}}/**
2 | * {{(index .Doc .Active.Name).Desc}}{{with (index .Doc .Active.Name).Args}}
3 | *{{end}}{{with $data := .}}{{range .Active.Args}}
4 | * @param "{{.}}" {{(index ((index $data.Doc $data.Active.Name).Args) .).Desc}}{{end}}{{end}}
5 | */
6 | var {{call .Fnc.camelize .Active.Name}} = function({{call .Fnc.args.node .Active.Args}}client) {
7 | {{range .Active.Args}} this.{{.}} = {{.}};
8 | {{end}} this.client = client;
9 |
10 | return this;
11 | };
12 | {{with $data := .}}{{range .Active.Functions}}
13 | /**
14 | * {{(index ((index $data.Doc $data.Active.Name).Functions) .Name).Desc}}
15 | *
16 | * '{{.Path}}' {{call $data.Fnc.upper (or .Method "get")}}{{with .Params}}
17 | *{{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
18 | * @param "{{.Name}}" {{(index ((index ((index $data.Doc $data.Active.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
19 | */
20 | {{call $data.Fnc.camelize $data.Active.Name}}.prototype.{{call $data.Fnc.camelizeDownFirst .Name}} = function ({{call $data.Fnc.args.node .Params}}options, callback) {
21 | if (typeof options === 'function') {
22 | callback = options;
23 | options = {};
24 | }
25 |
26 | var body = (options.{{template "boq" .}} ? options.{{template "boq" .}} : {});{{range .Params}}{{if .Required}}{{if (not .UrlUse)}}
27 | body['{{.Name}}'] = {{.Name}};{{end}}{{end}}{{end}}
28 |
29 | this.client.{{or .Method "get"}}('{{call $data.Fnc.path.node .Path $data.Active.Args .Params}}', body, options, function(err, response) {
30 | if (err) {
31 | return callback(err);
32 | }
33 |
34 | callback(null, response);
35 | });
36 | };
37 | {{end}}{{end}}
38 | // Export module
39 | module.exports = {{call .Fnc.camelize .Active.Name}};
40 |
--------------------------------------------------------------------------------
/templates/php/lib/HttpClient/ErrorHandler.php:
--------------------------------------------------------------------------------
1 | getResponse();
20 |
21 | $message = null;
22 | $code = $response->getStatusCode();
23 |
24 | if ($response->isServerError()) {
25 | throw new ClientException('Error '.$code, $code);
26 | }
27 |
28 | if ($response->isClientError()) {
29 | $body = ResponseHandler::getBody($response);
30 |
31 | // If HTML, whole body is taken
32 | if (gettype($body) == 'string') {
33 | $message = $body;
34 | }
35 | {{if .Api.Response.Formats.Json}}
36 | // If JSON, a particular field is taken and used
37 | if ($response->isContentType('json') && is_array($body)) {
38 | if (isset($body['{{.Api.Error.Message}}'])) {
39 | $message = $body['{{.Api.Error.Message}}'];
40 | } else {
41 | $message = 'Unable to select error message from json returned by request responsible for error';
42 | }
43 | }
44 | {{end}}
45 | if (empty($message)) {
46 | $message = 'Unable to understand the content type of response returned by request responsible for error';
47 | }
48 |
49 | throw new ClientException($message, $code);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/templates/php/lib/Api/Api.php:
--------------------------------------------------------------------------------
1 | {{.}} = ${{.}};
21 | {{end}} $this->client = $client;
22 | }
23 | {{with $data := .}}{{range .Active.Functions}}
24 | /**
25 | * {{(index ((index $data.Doc $data.Active.Name).Functions) .Name).Desc}}
26 | *
27 | * '{{.Path}}' {{call $data.Fnc.upper (or .Method "get")}}{{with .Params}}
28 | *{{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
29 | * @param ${{.Name}} {{(index ((index ((index $data.Doc $data.Active.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
30 | */
31 | public function {{call $data.Fnc.camelizeDownFirst .Name}}({{call $data.Fnc.args.php .Params}}array $options = array())
32 | {
33 | $body = (isset($options['{{template "boq" .}}']) ? $options['{{template "boq" .}}'] : array());{{range .Params}}{{if .Required}}{{if (not .UrlUse)}}
34 | $body['{{.Name}}'] = ${{.Name}};{{end}}{{end}}{{end}}
35 |
36 | $response = $this->client->{{or .Method "get"}}('{{call $data.Fnc.path.php .Path $data.Active.Args .Params}}', $body, $options);
37 |
38 | return $response;
39 | }
40 | {{end}}{{end}}
41 | }
42 |
--------------------------------------------------------------------------------
/alpaca/langs_node.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | )
6 |
7 | func WriteNode(data *Data) {
8 | MakeLibraryDir("node")
9 | RunTemplate := ChooseTemplate("node")
10 |
11 | RunTemplate("gitignore", ".gitignore", data)
12 | RunTemplate("package.json", "package.json", data)
13 | RunTemplate("readme.md", "README.md", data)
14 |
15 | MakeDir("lib")
16 | RunTemplate("lib/index.js", "index.js", data)
17 |
18 | MakeDir(inflect.Underscore(data.Pkg.Name))
19 | RunTemplate("lib/client.js", "client.js", data)
20 |
21 | MakeDir("error")
22 | RunTemplate("lib/error/index.js", "index.js", data)
23 | RunTemplate("lib/error/client_error.js", "client_error.js", data)
24 | MoveDir("..")
25 |
26 | MakeDir("http_client")
27 | RunTemplate("lib/http_client/index.js", "index.js", data)
28 | RunTemplate("lib/http_client/auth_handler.js", "auth_handler.js", data)
29 | RunTemplate("lib/http_client/error_handler.js", "error_handler.js", data)
30 | RunTemplate("lib/http_client/request_handler.js", "request_handler.js", data)
31 | RunTemplate("lib/http_client/response.js", "response.js", data)
32 | RunTemplate("lib/http_client/response_handler.js", "response_handler.js", data)
33 | MoveDir("..")
34 |
35 | MakeDir("api")
36 |
37 | for _, v := range data.Api.Classes {
38 | data.Active = &v
39 | RunTemplate("lib/api/api.js", inflect.Underscore(v.Name)+".js", data)
40 | data.Active = nil
41 | }
42 | }
43 |
44 | func FunctionsNode(fnc map[string]interface{}) {
45 | args := fnc["args"].(map[string]interface{})
46 | path := fnc["path"].(map[string]interface{})
47 | prnt := fnc["prnt"].(map[string]interface{})
48 |
49 | args["node"] = ArgsFunctionMaker("", ", ")
50 | path["node"] = PathFunctionMaker("' + ", "this.", " + '")
51 | prnt["node"] = PrntFunctionMaker(false, " ", "\"", "\"", "[", "]", "{", "}", "", ": ")
52 | }
53 |
54 | func CheckNode(data *Data) error {
55 | return nil
56 | }
57 |
--------------------------------------------------------------------------------
/alpaca/langs_python.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | )
6 |
7 | func WritePython(data *Data) {
8 | MakeLibraryDir("python")
9 | RunTemplate := ChooseTemplate("python")
10 |
11 | RunTemplate("gitignore", ".gitignore", data)
12 | RunTemplate("setup.py", "setup.py", data)
13 | RunTemplate("readme.md", "README.md", data)
14 |
15 | MakeDir(inflect.Underscore(data.Pkg.Name))
16 | RunTemplate("lib/__init__.py", "__init__.py", data)
17 | RunTemplate("lib/client.py", "client.py", data)
18 |
19 | MakeDir("error")
20 | RunTemplate("lib/error/__init__.py", "__init__.py", data)
21 | RunTemplate("lib/error/client_error.py", "client_error.py", data)
22 | MoveDir("..")
23 |
24 | MakeDir("http_client")
25 | RunTemplate("lib/http_client/__init__.py", "__init__.py", data)
26 | RunTemplate("lib/http_client/auth_handler.py", "auth_handler.py", data)
27 | RunTemplate("lib/http_client/error_handler.py", "error_handler.py", data)
28 | RunTemplate("lib/http_client/request_handler.py", "request_handler.py", data)
29 | RunTemplate("lib/http_client/response.py", "response.py", data)
30 | RunTemplate("lib/http_client/response_handler.py", "response_handler.py", data)
31 | MoveDir("..")
32 |
33 | MakeDir("api")
34 | RunTemplate("lib/api/__init__.py", "__init__.py", data)
35 |
36 | for _, v := range data.Api.Classes {
37 | data.Active = &v
38 | RunTemplate("lib/api/api.py", inflect.Underscore(v.Name)+".py", data)
39 | data.Active = nil
40 | }
41 | }
42 |
43 | func FunctionsPython(fnc map[string]interface{}) {
44 | args := fnc["args"].(map[string]interface{})
45 | path := fnc["path"].(map[string]interface{})
46 | prnt := fnc["prnt"].(map[string]interface{})
47 |
48 | args["python"] = ArgsFunctionMaker("", ", ")
49 | path["python"] = PathFunctionMaker("' + ", "self.", " + '")
50 | prnt["python"] = PrntFunctionMaker(true, " ", "\"", "\"", "[", "]", "{", "}", "'", "': ")
51 | }
52 |
53 | func CheckPython(data *Data) error {
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/alpaca/langs_ruby.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | )
6 |
7 | func WriteRuby(data *Data) {
8 | MakeLibraryDir("ruby")
9 | RunTemplate := ChooseTemplate("ruby")
10 |
11 | RunTemplate("gitignore", ".gitignore", data)
12 | RunTemplate("gemspec", data.Pkg.Package+".gemspec", data)
13 | RunTemplate("readme.md", "README.md", data)
14 |
15 | MakeDir("lib")
16 | RunTemplate("lib/name.rb", data.Pkg.Package+".rb", data)
17 |
18 | MakeDir(inflect.Underscore(data.Pkg.Name))
19 | RunTemplate("lib/client.rb", "client.rb", data)
20 | RunTemplate("lib/http_client.rb", "http_client.rb", data)
21 | RunTemplate("lib/error.rb", "error.rb", data)
22 | RunTemplate("lib/version.rb", "version.rb", data)
23 |
24 | MakeDir("error")
25 | RunTemplate("lib/error/client_error.rb", "client_error.rb", data)
26 | MoveDir("..")
27 |
28 | MakeDir("http_client")
29 | RunTemplate("lib/http_client/auth_handler.rb", "auth_handler.rb", data)
30 | RunTemplate("lib/http_client/error_handler.rb", "error_handler.rb", data)
31 | RunTemplate("lib/http_client/request_handler.rb", "request_handler.rb", data)
32 | RunTemplate("lib/http_client/response.rb", "response.rb", data)
33 | RunTemplate("lib/http_client/response_handler.rb", "response_handler.rb", data)
34 | MoveDir("..")
35 |
36 | MakeDir("api")
37 |
38 | for _, v := range data.Api.Classes {
39 | data.Active = &v
40 | RunTemplate("lib/api/api.rb", inflect.Underscore(v.Name)+".rb", data)
41 | data.Active = nil
42 | }
43 | }
44 |
45 | func FunctionsRuby(fnc map[string]interface{}) {
46 | args := fnc["args"].(map[string]interface{})
47 | path := fnc["path"].(map[string]interface{})
48 | prnt := fnc["prnt"].(map[string]interface{})
49 |
50 | args["ruby"] = ArgsFunctionMaker("", ", ")
51 | path["ruby"] = PathFunctionMaker("#{", "@", "}")
52 | prnt["ruby"] = PrntFunctionMaker(false, " ", "\"", "\"", "[", "]", "{", "}", ":", " => ")
53 | }
54 |
55 | func CheckRuby(data *Data) error {
56 | return nil
57 | }
58 |
--------------------------------------------------------------------------------
/alpaca/langs_php.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | "errors"
6 | )
7 |
8 | func WritePhp(data *Data) {
9 | MakeLibraryDir("php")
10 | RunTemplate := ChooseTemplate("php")
11 |
12 | RunTemplate("gitignore", ".gitignore", data)
13 | RunTemplate("composer.json", "composer.json", data)
14 | RunTemplate("readme.md", "README.md", data)
15 |
16 | MakeDir("lib")
17 |
18 | MakeDir(inflect.Camelize(data.Pkg.Name))
19 | RunTemplate("lib/Client.php", "Client.php", data)
20 |
21 | MakeDir("Exception")
22 | RunTemplate("lib/Exception/ExceptionInterface.php", "ExceptionInterface.php", data)
23 | RunTemplate("lib/Exception/ClientException.php", "ClientException.php", data)
24 | MoveDir("..")
25 |
26 | MakeDir("HttpClient")
27 | RunTemplate("lib/HttpClient/HttpClient.php", "HttpClient.php", data)
28 | RunTemplate("lib/HttpClient/AuthHandler.php", "AuthHandler.php", data)
29 | RunTemplate("lib/HttpClient/ErrorHandler.php", "ErrorHandler.php", data)
30 | RunTemplate("lib/HttpClient/RequestHandler.php", "RequestHandler.php", data)
31 | RunTemplate("lib/HttpClient/Response.php", "Response.php", data)
32 | RunTemplate("lib/HttpClient/ResponseHandler.php", "ResponseHandler.php", data)
33 | MoveDir("..")
34 |
35 | MakeDir("Api")
36 |
37 | for _, v := range data.Api.Classes {
38 | data.Active = &v
39 | RunTemplate("lib/Api/Api.php", inflect.Camelize(v.Name)+".php", data)
40 | data.Active = nil
41 | }
42 | }
43 |
44 | func FunctionsPhp(fnc map[string]interface{}) {
45 | args := fnc["args"].(map[string]interface{})
46 | path := fnc["path"].(map[string]interface{})
47 | prnt := fnc["prnt"].(map[string]interface{})
48 |
49 | args["php"] = ArgsFunctionMaker("$", ", ")
50 | path["php"] = PathFunctionMaker("'.rawurlencode($$", "this->", ").'")
51 | prnt["php"] = PrntFunctionMaker(false, " ", "\"", "\"", "array(", ")", "array(", ")", "'", "' => ")
52 | }
53 |
54 | func CheckPhp(data *Data) error {
55 | if data.Pkg.Php.Vendor == "" {
56 | return errors.New("php.vendor is needed in pkg.json for generating php library")
57 | }
58 |
59 | return nil
60 | }
61 |
--------------------------------------------------------------------------------
/templates/python/lib/http_client/request_handler.py:
--------------------------------------------------------------------------------
1 | import urllib
2 | import json
3 |
4 |
5 | class RequestHandler(object):
6 |
7 | """RequestHandler takes care of encoding the request body into format given by options"""
8 |
9 | @staticmethod
10 | def render_key(parents):
11 | depth, new = 0, ''
12 |
13 | for x in parents:
14 | old = '[%s]' if depth > 0 else '%s'
15 | new += old % x
16 | depth += 1
17 |
18 | return new
19 |
20 | @staticmethod
21 | def urlencode(data, parents=None, pairs=None):
22 | if pairs is None:
23 | pairs = {}
24 |
25 | if parents is None:
26 | parents = []
27 |
28 | if isinstance(data, dict):
29 | for key, value in data.items():
30 | RequestHandler.urlencode(value, parents + [key], pairs)
31 | elif isinstance(data, list):
32 | for key, value in enumerate(data):
33 | RequestHandler.urlencode(value, parents + [key], pairs)
34 | else:
35 | pairs[RequestHandler.render_key(parents)] = data
36 |
37 | return pairs
38 |
39 | @staticmethod
40 | def set_body(request):
41 | typ = request['request_type'] if 'request_type' in request else '{{or .Api.Request.Formats.Default "raw"}}'
42 | {{if .Api.Request.Formats.Json}}
43 | # Encoding request body into JSON format
44 | if typ == 'json':
45 | request['data'] = json.dumps(request['data'])
46 | request['headers']['content-type'] = 'application/json'
47 | {{end}}{{if .Api.Request.Formats.Form}}
48 | # Encoding body into form-urlencoded format
49 | if typ == 'form':
50 | request['data'] = RequestHandler.urlencode(request['data'])
51 | request['headers']['content-type'] = 'application/x-www-form-urlencoded'
52 | {{end}}
53 | if typ == 'raw':
54 | if 'content-type' in request['headers']:
55 | del request['headers']['content-type']
56 |
57 | if 'request_type' in request:
58 | del request['request_type']
59 |
60 | return request
61 |
--------------------------------------------------------------------------------
/alpaca/library.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "os"
5 | "path"
6 | )
7 |
8 | type PkgStruct struct {
9 | Name string
10 | Package string
11 | Version string
12 | Url string
13 |
14 | Keywords []string
15 | Official bool
16 | License string
17 |
18 | Author struct {
19 | Name string
20 | Email string
21 | Url string
22 | }
23 |
24 | Git struct {
25 | Site string
26 | User string
27 | Name string
28 | }
29 |
30 | Php struct {
31 | Vendor string
32 | }
33 |
34 | Python struct {
35 | License string
36 | }
37 | }
38 |
39 | type ApiParam struct {
40 | Name string
41 | Required bool
42 | UrlUse bool `json:"url_use"`
43 | }
44 |
45 | type ApiFunction struct {
46 | Name string
47 | Path string
48 | Method string
49 |
50 | Params []ApiParam
51 | }
52 |
53 | type ApiClass struct {
54 | Name string
55 | Args []string
56 |
57 | Functions []ApiFunction
58 | }
59 |
60 | type ApiStruct struct {
61 | Version string
62 | Base string
63 |
64 | BaseAsArg bool `json:"base_as_arg"`
65 | NoVerifySSL bool `json:"no_verify_ssl"`
66 |
67 | Authorization struct {
68 | Basic bool
69 | Oauth bool
70 | Header bool
71 |
72 | HeaderPrefix string `json:"header_prefix"`
73 | NeedAuth bool `json:"need_auth"`
74 | }
75 |
76 | Request struct {
77 | Formats struct {
78 | Default string
79 |
80 | Form bool
81 | Json bool
82 | }
83 | }
84 |
85 | Response struct {
86 | Suffix bool
87 |
88 | Formats struct {
89 | Default string
90 |
91 | Html bool
92 | Json bool
93 | }
94 | }
95 |
96 | Error struct {
97 | Message string
98 | }
99 |
100 | Classes []ApiClass
101 | }
102 |
103 | type DocParam struct {
104 | Desc string
105 | Value interface{}
106 | }
107 |
108 | type DocFunction struct {
109 | Title string
110 | Desc string
111 |
112 | Params map[string]DocParam
113 | }
114 |
115 | type DocClass struct {
116 | Title string
117 | Desc string
118 |
119 | Args map[string]DocParam
120 | Functions map[string]DocFunction
121 | }
122 |
123 | func MakeLibraryDir(name string) {
124 | name = path.Join(LibraryRoot, name)
125 |
126 | HandleError(os.RemoveAll(name))
127 | MakeDir(name)
128 | }
129 |
--------------------------------------------------------------------------------
/examples/helpful/api.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": "https://helpful.io",
3 | "version": "api",
4 | "authorization": {
5 | "need_auth": true,
6 | "basic": true,
7 | "oauth": true
8 | },
9 | "request": {
10 | "formats": {
11 | "default": "json",
12 | "json": true
13 | }
14 | },
15 | "response": {
16 | "formats": {
17 | "default": "json",
18 | "json": true
19 | }
20 | },
21 | "error": {
22 | "message": "error"
23 | },
24 | "classes": [
25 | {
26 | "name": "accounts",
27 | "functions": [
28 | {
29 | "name": "all",
30 | "path": "/accounts"
31 | },
32 | {
33 | "name": "get",
34 | "path": "/accounts/:account_id",
35 | "params": [
36 | {
37 | "name": "account_id",
38 | "required": true,
39 | "url_use": true
40 | }
41 | ]
42 | },
43 | {
44 | "name": "update",
45 | "path": "/accounts/:account_id",
46 | "method": "patch",
47 | "params": [
48 | {
49 | "name": "account_id",
50 | "required": true,
51 | "url_use": true
52 | }
53 | ]
54 | }
55 | ]
56 | },
57 | {
58 | "name": "people",
59 | "functions": [
60 | {
61 | "name": "all",
62 | "path": "/accounts/:account_id/people",
63 | "params": [
64 | {
65 | "name": "account_id",
66 | "required": true,
67 | "url_use": true
68 | }
69 | ]
70 | }
71 | ]
72 | },
73 | {
74 | "name": "conversations",
75 | "functions": [
76 | {
77 | "name": "all",
78 | "path": "/accounts/:account_id/conversations",
79 | "params": [
80 | {
81 | "name": "account_id",
82 | "required": true,
83 | "url_use": true
84 | },
85 | {
86 | "name": "archived"
87 | }
88 | ]
89 | },
90 | {
91 | "name": "create",
92 | "path": "/accounts/:account_id/conversations",
93 | "method": "post",
94 | "params": [
95 | {
96 | "name": "account_id",
97 | "required": true,
98 | "url_use": true
99 | }
100 | ]
101 | },
102 | {
103 | "name": "get",
104 | "path": "/conversations/:conversation_id",
105 | "params": [
106 | {
107 | "name": "conversation_id",
108 | "required": true,
109 | "url_use": true
110 | }
111 | ]
112 | }
113 | ]
114 | },
115 | {
116 | "name": "messages",
117 | "functions": [
118 | {
119 | "name": "get",
120 | "path": "/messages/:message_id",
121 | "params": [
122 | {
123 | "name": "message_id",
124 | "required": true,
125 | "url_use": true
126 | }
127 | ]
128 | }
129 | ]
130 | }
131 | ]
132 | }
133 |
--------------------------------------------------------------------------------
/alpaca/alpaca.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | "fmt"
6 | "os"
7 | "path/filepath"
8 | "strings"
9 | )
10 |
11 | const (
12 | Version = "0.2.1"
13 | )
14 |
15 | var (
16 | LibraryRoot string
17 | FormatList []string
18 | )
19 |
20 | type Data struct {
21 | Pkg PkgStruct
22 | Api ApiStruct
23 | Doc map[string]DocClass
24 |
25 | Fnc map[string]interface{}
26 |
27 | Version string /* Alpaca version to be used in user_agent */
28 | Active *ApiClass /* Current class info needed to keep context */
29 | }
30 |
31 | type LanguageOptions struct {
32 | Php bool `long:"no-php" description:"Do not write php library"`
33 | Python bool `long:"no-python" description:"Do not write python library"`
34 | Ruby bool `long:"no-ruby" description:"Do not write ruby library"`
35 | Node bool `long:"no-node" description:"Do not write node library"`
36 | }
37 |
38 | func LoadLibraryPath(directory string) {
39 | var err error
40 |
41 | LibraryRoot, err = filepath.Abs(directory)
42 | HandleError(err)
43 | }
44 |
45 | func ConvertFormat(format string) {
46 | acceptable := false
47 |
48 | FormatList = []string{}
49 |
50 | for _, v := range FormatList {
51 | if v == format {
52 | acceptable = true
53 | }
54 | }
55 |
56 | if !acceptable {
57 | fmt.Println("The given format is not allowed. Please choose one from the following:")
58 | fmt.Println()
59 | fmt.Println(strings.Join(FormatList, ", ") + "\n")
60 | os.Exit(0)
61 | }
62 | }
63 |
64 | func WriteLibraries(opts *LanguageOptions) {
65 | data := ReadData()
66 | ModifyData(data)
67 |
68 | if !opts.Php {
69 | HandleError(CheckPhp(data))
70 | FunctionsPhp(data.Fnc)
71 | WritePhp(data)
72 | }
73 |
74 | if !opts.Python {
75 | HandleError(CheckPython(data))
76 | FunctionsPython(data.Fnc)
77 | WritePython(data)
78 | }
79 |
80 | if !opts.Ruby {
81 | HandleError(CheckRuby(data))
82 | FunctionsRuby(data.Fnc)
83 | WriteRuby(data)
84 | }
85 |
86 | if !opts.Node {
87 | HandleError(CheckNode(data))
88 | FunctionsNode(data.Fnc)
89 | WriteNode(data)
90 | }
91 | }
92 |
93 | func ReadData() *Data {
94 | var pkg PkgStruct
95 | var api ApiStruct
96 | var doc map[string]DocClass
97 |
98 | ReadJSON("pkg.json", &pkg)
99 | ReadJSON("api.json", &api)
100 | ReadJSON("doc.json", &doc)
101 |
102 | return &Data{pkg, api, doc, make(map[string]interface{}), Version, nil}
103 | }
104 |
105 | func ModifyData(data *Data) {
106 | data.Fnc["join"] = strings.Join
107 | data.Fnc["upper"] = strings.ToUpper
108 |
109 | data.Fnc["camelize"] = inflect.Camelize
110 | data.Fnc["camelizeDownFirst"] = inflect.CamelizeDownFirst
111 | data.Fnc["underscore"] = inflect.Underscore
112 |
113 | data.Fnc["args"] = make(map[string]interface{})
114 | data.Fnc["path"] = make(map[string]interface{})
115 | data.Fnc["prnt"] = make(map[string]interface{})
116 | }
117 |
--------------------------------------------------------------------------------
/examples/helpful/doc.json:
--------------------------------------------------------------------------------
1 | {
2 | "accounts": {
3 | "title": "Accounts",
4 | "desc": "These are like organizations which use Helpful.",
5 | "functions": {
6 | "all": {
7 | "title": "List all accounts",
8 | "desc": "All the accounts the user has access to"
9 | },
10 | "get": {
11 | "title": "Retrieve an account",
12 | "desc": "Get an account the user has access to",
13 | "params": {
14 | "account_id": {
15 | "desc": "Identifier of the account",
16 | "value": "b3ebe711-755e-4a91-b8d2-0cc028827bcf"
17 | }
18 | }
19 | },
20 | "update": {
21 | "title": "Update an account",
22 | "desc": "Update an account the user has access to",
23 | "params": {
24 | "account_id": {
25 | "desc": "Identifier of the account",
26 | "value": "b3ebe711-755e-4a91-b8d2-0cc028827bcf"
27 | }
28 | }
29 | }
30 | }
31 | },
32 | "people": {
33 | "title": "People",
34 | "desc": "People who operate or interacted with the account",
35 | "functions": {
36 | "all": {
37 | "title": "List all people",
38 | "desc": "List all people in the account the user has access to",
39 | "params": {
40 | "account_id": {
41 | "desc": "Identifier of the account",
42 | "value": "b3ebe711-755e-4a91-b8d2-0cc028827bcf"
43 | }
44 | }
45 | }
46 | }
47 | },
48 | "conversations": {
49 | "title": "Conversations",
50 | "desc": "Conversations in an account",
51 | "functions": {
52 | "all": {
53 | "title": "List all conversations",
54 | "desc": "List all conversations in an account the user has access to",
55 | "params": {
56 | "account_id": {
57 | "desc": "Identifier of the account",
58 | "value": "b3ebe711-755e-4a91-b8d2-0cc028827bcf"
59 | },
60 | "archived": {
61 | "desc": "Archived if true, not if false",
62 | "value": "false"
63 | }
64 | }
65 | },
66 | "create": {
67 | "title": "Create a conversation",
68 | "desc": "Create an empty conversation in account the user has access to",
69 | "params": {
70 | "account_id": {
71 | "desc": "Identifier of the account",
72 | "value": "b3ebe711-755e-4a91-b8d2-0cc028827bcf"
73 | }
74 | }
75 | },
76 | "get": {
77 | "title": "Retrieve a conversation",
78 | "desc": "Get a conversation the user has access to",
79 | "params": {
80 | "conversation_id": {
81 | "desc": "Identifier of the conversation",
82 | "value": "10ce24de-23f6-433f-9a71-255cffffa96f"
83 | }
84 | }
85 | }
86 | }
87 | },
88 | "messages": {
89 | "title": "Messages",
90 | "desc": "Messages in a conversation",
91 | "functions": {
92 | "get": {
93 | "title": "Retrieve a message",
94 | "desc": "Get a message the user has access to",
95 | "params": {
96 | "message_id": {
97 | "desc": "Identifier of the message",
98 | "value": "33314e4e-baf5-4b33-be72-112ed86701fd"
99 | }
100 | }
101 | }
102 | }
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/templates/python/lib/http_client/auth_handler.py:
--------------------------------------------------------------------------------
1 | class AuthHandler(object):
2 |
3 | """AuthHandler takes care of devising the auth type and using it"""
4 | {{if .Api.Authorization.Basic}}
5 | HTTP_PASSWORD = 0
6 | {{end}}{{if .Api.Authorization.Header}}
7 | HTTP_HEADER = 1
8 | {{end}}{{if .Api.Authorization.Oauth}}
9 | URL_SECRET = 2
10 | URL_TOKEN = 3
11 | {{end}}
12 | def __init__(self, auth):
13 | self.auth = auth
14 |
15 | def get_auth_type(self):
16 | """Calculating the Authentication Type"""
17 | {{if .Api.Authorization.Basic}}
18 | if 'username' in self.auth and 'password' in self.auth:
19 | return self.HTTP_PASSWORD
20 | {{end}}{{if .Api.Authorization.Header}}
21 | if 'http_header' in self.auth:
22 | return self.HTTP_HEADER
23 | {{end}}{{if .Api.Authorization.Oauth}}
24 | if 'client_id' in self.auth and 'client_secret' in self.auth:
25 | return self.URL_SECRET
26 |
27 | if 'access_token' in self.auth:
28 | return self.URL_TOKEN
29 | {{end}}
30 | return -1
31 |
32 | def set(self, request):
33 | if len(self.auth.keys()) == 0:{{if .Api.Authorization.NeedAuth}}
34 | raise StandardError("Server requires authentication to proceed further. Please check"){{else}}
35 | return request{{end}}
36 |
37 | auth = self.get_auth_type()
38 | flag = False
39 | {{if .Api.Authorization.Basic}}
40 | if auth == self.HTTP_PASSWORD:
41 | request = self.http_password(request)
42 | flag = True
43 | {{end}}{{if .Api.Authorization.Header}}
44 | if auth == self.HTTP_HEADER:
45 | request = self.http_header(request)
46 | flag = True
47 | {{end}}{{if .Api.Authorization.Oauth}}
48 | if auth == self.URL_SECRET:
49 | request = self.url_secret(request)
50 | flag = True
51 |
52 | if auth == self.URL_TOKEN:
53 | request = self.url_token(request)
54 | flag = True
55 | {{end}}
56 | if not flag:
57 | raise StandardError("Unable to calculate authorization method. Please check")
58 |
59 | return request
60 | {{if .Api.Authorization.Basic}}
61 | def http_password(self, request):
62 | """Basic Authorization with username and password"""
63 | request['auth'] = (self.auth['username'], self.auth['password'])
64 | return request
65 | {{end}}{{if .Api.Authorization.Header}}
66 | def http_header(self, request):
67 | """Authorization with HTTP header"""
68 | request['headers']['Authorization'] = '{{or .Api.Authorization.HeaderPrefix "token"}} ' + self.auth['http_header']
69 | return request
70 | {{end}}{{if .Api.Authorization.Oauth}}
71 | def url_secret(self, request):
72 | """OAUTH2 Authorization with client secret"""
73 | request['params']['client_id'] = self.auth['client_id']
74 | request['params']['client_secret'] = self.auth['client_secret']
75 | return request
76 |
77 | def url_token(self, request):
78 | """OAUTH2 Authorization with access token"""
79 | request['params']['access_token'] = self.auth['access_token']
80 | return request
81 | {{end}}
82 |
--------------------------------------------------------------------------------
/templates/node/lib/http_client/auth_handler.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This module takes care of devising the auth type and using it
3 | */
4 | var Auth = function(auth) {
5 | this.auth = auth;
6 | {{if .Api.Authorization.Basic}}
7 | this.HTTP_PASSWORD = 0;
8 | {{end}}{{if .Api.Authorization.Header}}
9 | this.HTTP_HEADER = 1;
10 | {{end}}{{if .Api.Authorization.Oauth}}
11 | this.URL_SECRET = 2;
12 | this.URL_TOKEN = 3;
13 | {{end}}
14 | return this;
15 | };
16 |
17 | /**
18 | * Calculating the type of authentication
19 | */
20 | Auth.prototype.getAuthType = function () {
21 | {{if .Api.Authorization.Basic}}
22 | if (this.auth.username && this.auth.password) {
23 | return this.HTTP_PASSWORD;
24 | }
25 | {{end}}{{if .Api.Authorization.Header}}
26 | if (this.auth.http_header) {
27 | return this.HTTP_HEADER;
28 | }
29 | {{end}}{{if .Api.Authorization.Oauth}}
30 | if (this.auth.client_id && this.auth.client_secret) {
31 | return this.URL_SECRET;
32 | }
33 |
34 | if (this.auth.access_token) {
35 | return this.URL_TOKEN;
36 | }
37 | {{end}}
38 | return -1;
39 | };
40 |
41 | /**
42 | * Set authentication for the request
43 | *
44 | * This should throw error because this should be caught while in development
45 | */
46 | Auth.prototype.set = function (request, callback) {
47 | if (Object.keys(this.auth).length === 0) {
48 | return callback({{if .Api.Authorization.NeedAuth}}new Error('Server requires authentication to proceed further. Please check'));
49 | {{else}}null, request);
50 | {{end}}}
51 |
52 | var auth = this.getAuthType(), flag = false;
53 | {{if .Api.Authorization.Basic}}
54 | if (auth === this.HTTP_PASSWORD) {
55 | request = this.httpPassword(request);
56 | flag = true;
57 | }
58 | {{end}}{{if .Api.Authorization.Header}}
59 | if (auth == this.HTTP_HEADER) {
60 | request = this.httpHeader(request);
61 | flag = true;
62 | }
63 | {{end}}{{if .Api.Authorization.Oauth}}
64 | if (auth == this.URL_SECRET) {
65 | request = this.urlSecret(request);
66 | flag = true;
67 | }
68 |
69 | if (auth == this.URL_TOKEN) {
70 | request = this.urlToken(request);
71 | flag = true;
72 | }
73 | {{end}}
74 | if (!flag) {
75 | return callback(new Error('Unable to calculate authorization method. Please check.'));
76 | }
77 |
78 | callback(null, request);
79 | };
80 | {{if .Api.Authorization.Basic}}
81 | /**
82 | * Basic Authorization with username and password
83 | */
84 | Auth.prototype.httpPassword = function(request) {
85 | request.auth = this.auth;
86 |
87 | return request;
88 | };
89 | {{end}}{{if .Api.Authorization.Header}}
90 | /**
91 | * Authorization with HTTP header
92 | */
93 | Auth.prototype.httpHeader = function(request) {
94 | request['headers']['Authorization'] = '{{or .Api.Authorization.HeaderPrefix "token"}} ' + this.auth['http_header'];
95 |
96 | return request;
97 | };
98 | {{end}}{{if .Api.Authorization.Oauth}}
99 | /**
100 | * OAUTH2 Authorization with client secret
101 | */
102 | Auth.prototype.urlSecret = function(request) {
103 | request['qs']['client_id'] = this.auth['client_id'];
104 | request['qs']['client_secret'] = this.auth['client_secret'];
105 |
106 | return request;
107 | };
108 |
109 | /**
110 | * OAUTH2 Authorization with access token
111 | */
112 | Auth.prototype.urlToken = function(request) {
113 | request['qs']['access_token'] = this.auth['access_token'];
114 |
115 | return request;
116 | };
117 | {{end}}
118 | // Export module
119 | module.exports = Auth;
120 |
--------------------------------------------------------------------------------
/examples/buffer/api.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": "https://api.bufferapp.com",
3 | "version": "1",
4 | "authorization": {
5 | "need_auth": true,
6 | "oauth": true
7 | },
8 | "request": {
9 | "formats": {
10 | "default": "form",
11 | "form": true
12 | }
13 | },
14 | "response": {
15 | "formats": {
16 | "default": "json",
17 | "json": true
18 | },
19 | "suffix": true
20 | },
21 | "error": {
22 | "message": "error"
23 | },
24 | "classes": [
25 | {
26 | "name": "info",
27 | "functions": [
28 | {
29 | "name": "show",
30 | "path": "/info/configuration"
31 | }
32 | ]
33 | },
34 | {
35 | "name": "user",
36 | "functions": [
37 | {
38 | "name": "show",
39 | "path": "/user"
40 | },
41 | {
42 | "name": "profiles",
43 | "path": "/profiles"
44 | },
45 | {
46 | "name": "create_update",
47 | "path": "/updates/create",
48 | "method": "post",
49 | "params": [
50 | {
51 | "name": "text",
52 | "required": true
53 | },
54 | {
55 | "name": "profile_ids",
56 | "required": true
57 | }
58 | ]
59 | }
60 | ]
61 | },
62 | {
63 | "name": "link",
64 | "functions": [
65 | {
66 | "name": "shares",
67 | "path": "/link/shares",
68 | "params": [
69 | {
70 | "name": "url",
71 | "required": true
72 | }
73 | ]
74 | }
75 | ]
76 | },
77 | {
78 | "name": "profile",
79 | "args": ["id"],
80 | "functions": [
81 | {
82 | "name": "show",
83 | "path": "/profiles/:id"
84 | },
85 | {
86 | "name": "pending",
87 | "path": "/profiles/:id/updates/pending",
88 | "paginate": true
89 | },
90 | {
91 | "name": "sent",
92 | "path": "/profiles/:id/updates/sent",
93 | "paginate": true
94 | },
95 | {
96 | "name": "reorder",
97 | "path": "/profiles/:id/updates/reorder",
98 | "method": "post",
99 | "params": [
100 | {
101 | "name": "order",
102 | "required": true
103 | }
104 | ]
105 | },
106 | {
107 | "name": "shuffle",
108 | "path": "/profiles/:id/updates/shuffle",
109 | "method": "post"
110 | }
111 | ]
112 | },
113 | {
114 | "name": "schedule",
115 | "args": ["id"],
116 | "functions": [
117 | {
118 | "name": "list",
119 | "path": "/profiles/:id/schedules"
120 | },
121 | {
122 | "name": "update",
123 | "path": "/profiles/:id/schedules/update",
124 | "method": "post",
125 | "params": [
126 | {
127 | "name": "schedules",
128 | "required": true
129 | }
130 | ]
131 | }
132 | ]
133 | },
134 | {
135 | "name": "update",
136 | "args": ["id"],
137 | "functions": [
138 | {
139 | "name": "show",
140 | "path": "/updates/:id"
141 | },
142 | {
143 | "name": "interactions",
144 | "path": "/updates/:id/interactions",
145 | "paginate": true
146 | },
147 | {
148 | "name": "update",
149 | "path": "/updates/:id/update",
150 | "method": "post",
151 | "params": [
152 | {
153 | "name": "text",
154 | "required": true
155 | }
156 | ]
157 | },
158 | {
159 | "name": "share",
160 | "path": "/updates/:id/share",
161 | "method": "post"
162 | },
163 | {
164 | "name": "destroy",
165 | "path": "/updates/:id/destroy",
166 | "method": "post"
167 | },
168 | {
169 | "name": "top",
170 | "path": "/updates/:id/move_to_top",
171 | "method": "post"
172 | }
173 | ]
174 | }
175 | ]
176 | }
177 |
--------------------------------------------------------------------------------
/alpaca/utils_test.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "github.com/robertkrimen/terst"
5 | "testing"
6 | )
7 |
8 | func TestArgsFunctionMaker(t *testing.T) {
9 | terst.Terst(t)
10 |
11 | f := ArgsFunctionMaker("$", ", ").(func(interface{}, ...bool) string)
12 |
13 | args := []string{"id", "url"}
14 | params := make([]ApiParam, 2)
15 |
16 | nulArgs := []string{}
17 | nulParams := make([]ApiParam, 0)
18 |
19 | params[0] = ApiParam{"id", true, false}
20 | params[1] = ApiParam{"url", false, false}
21 |
22 | terst.Is(f(args), "$id, $url, ")
23 | terst.Is(f(args, false), "$id, $url, ")
24 | terst.Is(f(args, true), "$id, $url")
25 | terst.Is(f(args, true, false), "$id, $url")
26 | terst.Is(f(args, true, true), ", $id, $url")
27 | terst.Is(f(args, false, true), ", $id, $url, ")
28 |
29 | terst.Is(f(params), "$id, ")
30 | terst.Is(f(params, true), "$id")
31 | terst.Is(f(params, false, true), ", $id, ")
32 |
33 | terst.Is(f(nulArgs), "")
34 | terst.Is(f(nulArgs, true), "")
35 | terst.Is(f(nulArgs, false, true), "")
36 |
37 | terst.Is(f(nulParams), "")
38 | terst.Is(f(nulParams, true), "")
39 | terst.Is(f(nulParams, false, true), "")
40 | }
41 |
42 | func TestPathFunctionMaker(t *testing.T) {
43 | terst.Terst(t)
44 |
45 | f := PathFunctionMaker("\"+", "@", "+\"").(func(string, []string, []ApiParam) string)
46 |
47 | cargs := []string{"id", "url"}
48 | margs := make([]ApiParam, 1)
49 |
50 | margs[0] = ApiParam{"one", false, false}
51 |
52 | terst.Is(f("/user/:id/:not/:url/wow:one", cargs, margs), "/user/\"+@id+\"/:not/\"+@url+\"/wow\"+one+\"")
53 | }
54 |
55 | func TestPrntFunctionMaker(t *testing.T) {
56 | terst.Terst(t)
57 |
58 | f := PrntFunctionMaker(true, " ", "'", "'", "[", "]", "{", "}", ":", " => ").(func(interface{}, map[string]DocParam, string, bool) string)
59 |
60 | apis := []string{"id"}
61 | apip := make([]ApiParam, 2)
62 | docs := make(map[string]DocParam)
63 | vals := make(map[string]interface{})
64 | orgs := make([]interface{}, 3)
65 | null := make(map[string]string)
66 |
67 | orgs[0] = false
68 | orgs[1] = "alpaca-api"
69 | orgs[2] = 00
70 |
71 | apip[0] = ApiParam{"id", true, false}
72 | apip[1] = ApiParam{"flag", false, false}
73 |
74 | docs["flag"] = DocParam{"", false}
75 |
76 | terst.Is(f([]string{}, make(map[string]DocParam), ", ", true), "")
77 | terst.Is(f([]ApiParam{}, make(map[string]DocParam), ", ", true), "")
78 | terst.Is(f([]int{}, make(map[string]DocParam), ", ", true), "")
79 |
80 | vals["key"] = 3737
81 | docs["id"] = DocParam{"", vals}
82 | terst.Is(f(apis, docs, ", ", true), "{\n :key => 3737\n}, ")
83 | terst.Is(f(apip, docs, ", ", true), "{\n :key => 3737\n}, ")
84 |
85 | vals["key"] = 1.99
86 | docs["id"] = DocParam{"", vals}
87 | terst.Is(f(apis, docs, ", ", false), "{\n :key => 1.99\n}")
88 | terst.Is(f(apip, docs, ", ", false), "{\n :key => 1.99\n}")
89 |
90 | vals["key"] = "pksunkara"
91 | docs["id"] = DocParam{"", vals}
92 | terst.Is(f(apis, docs, ", ", false), "{\n :key => 'pksunkara'\n}")
93 | terst.Is(f(apip, docs, ", ", false), "{\n :key => 'pksunkara'\n}")
94 |
95 | vals["key"] = true
96 | docs["id"] = DocParam{"", vals}
97 | terst.Is(f(apis, docs, ", ", false), "{\n :key => True\n}")
98 | terst.Is(f(apip, docs, ", ", false), "{\n :key => True\n}")
99 |
100 | vals["key"] = orgs
101 | docs["id"] = DocParam{"", vals}
102 | terst.Is(f(apis, docs, ", ", false), "{\n :key => [\n False,\n 'alpaca-api',\n 0\n ]\n}")
103 | terst.Is(f(apip, docs, ", ", false), "{\n :key => [\n False,\n 'alpaca-api',\n 0\n ]\n}")
104 |
105 | vals["key"] = null
106 | docs["id"] = DocParam{"", vals}
107 | terst.Is(f(apis, docs, ", ", false), "{\n :key => \n}")
108 | terst.Is(f(apip, docs, ", ", false), "{\n :key => \n}")
109 | }
110 |
--------------------------------------------------------------------------------
/templates/php/lib/HttpClient/AuthHandler.php:
--------------------------------------------------------------------------------
1 | auth = $auth;
24 | }
25 |
26 | /**
27 | * Calculating the Authentication Type
28 | */
29 | public function getAuthType()
30 | {
31 | {{if .Api.Authorization.Basic}}
32 | if (isset($this->auth['username']) && isset($this->auth['password'])) {
33 | return self::HTTP_PASSWORD;
34 | }
35 | {{end}}{{if .Api.Authorization.Header}}
36 | if (isset($this->auth['http_header'])) {
37 | return self::HTTP_HEADER;
38 | }
39 | {{end}}{{if .Api.Authorization.Oauth}}
40 | if (isset($this->auth['client_id']) && isset($this->auth['client_secret'])) {
41 | return self::URL_SECRET;
42 | }
43 |
44 | if (isset($this->auth['access_token'])) {
45 | return self::URL_TOKEN;
46 | }
47 | {{end}}
48 | return -1;
49 | }
50 |
51 | public function onRequestBeforeSend(Event $event)
52 | {
53 | if (empty($this->auth)) {
54 | {{if .Api.Authorization.NeedAuth}} throw new \ErrorException('Server requires authentication to proceed further. Please check');
55 | {{else}} return;
56 | {{end}}}
57 |
58 | $auth = $this->getAuthType();
59 | $flag = false;
60 | {{if .Api.Authorization.Basic}}
61 | if ($auth == self::HTTP_PASSWORD) {
62 | $this->httpPassword($event);
63 | $flag = true;
64 | }
65 | {{end}}{{if .Api.Authorization.Header}}
66 | if ($auth == self::HTTP_HEADER) {
67 | $this->httpHeader($event);
68 | $flag = true;
69 | }
70 | {{end}}{{if .Api.Authorization.Oauth}}
71 | if ($auth == self::URL_SECRET) {
72 | $this->urlSecret($event);
73 | $flag = true;
74 | }
75 |
76 | if ($auth == self::URL_TOKEN) {
77 | $this->urlToken($event);
78 | $flag = true;
79 | }
80 | {{end}}
81 | if (!$flag) {
82 | throw new \ErrorException('Unable to calculate authorization method. Please check.');
83 | }
84 | }
85 | {{if .Api.Authorization.Basic}}
86 | /**
87 | * Basic Authorization with username and password
88 | */
89 | public function httpPassword(Event $event)
90 | {
91 | $event['request']->setHeader('Authorization', sprintf('Basic %s', base64_encode($this->auth['username'] . ':' . $this->auth['password'])));
92 | }
93 | {{end}}{{if .Api.Authorization.Header}}
94 | /**
95 | * Authorization with HTTP header
96 | */
97 | public function httpHeader(Event $event)
98 | {
99 | $event['request']->setHeader('Authorization', sprintf('{{or .Api.Authorization.HeaderPrefix "token"}} %s', $this->auth['http_header']));
100 | }
101 | {{end}}{{if .Api.Authorization.Oauth}}
102 | /**
103 | * OAUTH2 Authorization with client secret
104 | */
105 | public function urlSecret(Event $event)
106 | {
107 | $query = $event['request']->getQuery();
108 |
109 | $query->set('client_id', $this->auth['client_id']);
110 | $query->set('client_secret', $this->auth['client_secret']);
111 | }
112 |
113 | /**
114 | * OAUTH2 Authorization with access token
115 | */
116 | public function urlToken(Event $event)
117 | {
118 | $query = $event['request']->getQuery();
119 |
120 | $query->set('access_token', $this->auth['access_token']);
121 | }
122 | {{end}}
123 | }
124 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client/auth_handler.rb:
--------------------------------------------------------------------------------
1 | require "base64"
2 |
3 | module {{call .Fnc.camelize .Pkg.Name}}
4 |
5 | module HttpClient
6 |
7 | # AuthHandler takes care of devising the auth type and using it
8 | class AuthHandler < Faraday::Middleware
9 | {{if .Api.Authorization.Basic}}
10 | HTTP_PASSWORD = 0
11 | {{end}}{{if .Api.Authorization.Header}}
12 | HTTP_HEADER = 1
13 | {{end}}{{if .Api.Authorization.Oauth}}
14 | URL_SECRET = 2
15 | URL_TOKEN = 3
16 | {{end}}
17 | def initialize(app, auth = {}, options = {})
18 | @auth = auth
19 | super(app)
20 | end
21 |
22 | def call(env)
23 | if !@auth.empty?
24 | auth = get_auth_type
25 | flag = false
26 | {{if .Api.Authorization.Basic}}
27 | if auth == HTTP_PASSWORD
28 | env = http_password(env)
29 | flag = true
30 | end
31 | {{end}}{{if .Api.Authorization.Header}}
32 | if auth == HTTP_HEADER
33 | env = http_header(env)
34 | flag = true
35 | end
36 | {{end}}{{if .Api.Authorization.Oauth}}
37 | if auth == URL_SECRET
38 | env = url_secret(env)
39 | flag = true
40 | end
41 |
42 | if auth == URL_TOKEN
43 | env = url_token(env)
44 | flag = true
45 | end
46 | {{end}}
47 | if !flag
48 | raise StandardError.new "Unable to calculate authorization method. Please check"
49 | end{{if .Api.Authorization.NeedAuth}}
50 | else
51 | raise StandardError.new "Server requires authentication to proceed further. Please check"{{end}}
52 | end
53 |
54 | @app.call(env)
55 | end
56 |
57 | # Calculating the Authentication Type
58 | def get_auth_type()
59 | {{if .Api.Authorization.Basic}}
60 | if @auth.has_key?(:username) and @auth.has_key?(:password)
61 | return HTTP_PASSWORD
62 | end
63 | {{end}}{{if .Api.Authorization.Header}}
64 | if @auth.has_key?(:http_header)
65 | return HTTP_HEADER
66 | end
67 | {{end}}{{if .Api.Authorization.Oauth}}
68 | if @auth.has_key?(:client_id) and @auth.has_key?(:client_secret)
69 | return URL_SECRET
70 | end
71 |
72 | if @auth.has_key?(:access_token)
73 | return URL_TOKEN
74 | end
75 | {{end}}
76 | return -1
77 | end
78 | {{if .Api.Authorization.Basic}}
79 | # Basic Authorization with username and password
80 | def http_password(env)
81 | code = Base64.strict_encode64 "#{@auth[:username]}:#{@auth[:password]}"
82 |
83 | env[:request_headers]["Authorization"] = "Basic #{code}"
84 |
85 | return env
86 | end
87 | {{end}}{{if .Api.Authorization.Header}}
88 | # Authorization with HTTP header
89 | def http_header(env)
90 | env[:request_headers]["Authorization"] = "{{or .Api.Authorization.HeaderPrefix "token"}} #{@auth[:http_header]}"
91 |
92 | return env
93 | end
94 | {{end}}{{if .Api.Authorization.Oauth}}
95 | # OAUTH2 Authorization with client secret
96 | def url_secret(env)
97 | query = {
98 | :client_id => @auth[:client_id],
99 | :client_secret => @auth[:client_secret]
100 | }
101 |
102 | merge_query(env, query)
103 | end
104 |
105 | # OAUTH2 Authorization with access token
106 | def url_token(env)
107 | query = { :access_token => @auth[:access_token] }
108 |
109 | merge_query(env, query)
110 | end
111 | {{end}}
112 | def query_params(url)
113 | if url.query.nil? or url.query.empty?
114 | {}
115 | else
116 | Faraday::Utils.parse_query(url.query)
117 | end
118 | end
119 |
120 | def merge_query(env, query)
121 | query = query.update query_params(env[:url])
122 |
123 | env[:url].query = Faraday::Utils.build_query(query)
124 |
125 | return env
126 | end
127 | end
128 |
129 | end
130 |
131 | end
132 |
--------------------------------------------------------------------------------
/alpaca/utils.go:
--------------------------------------------------------------------------------
1 | package alpaca
2 |
3 | import (
4 | "bitbucket.org/pkg/inflect"
5 | "encoding/json"
6 | "os"
7 | "path"
8 | "reflect"
9 | "regexp"
10 | "strconv"
11 | )
12 |
13 | func ReadJSON(name string, v interface{}) {
14 | file, err := os.Open(path.Join(LibraryRoot, name))
15 | HandleError(err)
16 |
17 | HandleError(json.NewDecoder(file).Decode(v))
18 | }
19 |
20 | func MakeDir(name string) {
21 | HandleError(os.Mkdir(name, 0755))
22 | MoveDir(name)
23 | }
24 |
25 | func MoveDir(name string) {
26 | HandleError(os.Chdir(name))
27 | }
28 |
29 | func ArgsFunctionMaker(before, after string) interface{} {
30 | return func(args interface{}, options ...bool) string {
31 | str := ""
32 |
33 | if reflect.TypeOf(args).String() == "[]string" {
34 | for _, v := range args.([]string) {
35 | str += before + v + after
36 | }
37 | } else {
38 | for _, v := range args.([]ApiParam) {
39 | if v.Required {
40 | str += before + v.Name + after
41 | }
42 | }
43 | }
44 |
45 | if str != "" {
46 | if len(options) > 0 && options[0] {
47 | str = str[0 : len(str)-len(after)]
48 | }
49 |
50 | if len(options) > 1 && options[1] {
51 | str = after + str
52 | }
53 | }
54 |
55 | return str
56 | }
57 | }
58 |
59 | func PathFunctionMaker(before, this, after string) interface{} {
60 | return func(path string, cargs []string, margs []ApiParam) string {
61 | for _, v := range cargs {
62 | reg := regexp.MustCompile(":(" + v + ")")
63 | path = reg.ReplaceAllString(path, before+this+"$1"+after)
64 | }
65 |
66 | for _, v := range margs {
67 | reg := regexp.MustCompile(":(" + v.Name + ")")
68 | path = reg.ReplaceAllString(path, before+"$1"+after)
69 | }
70 |
71 | return path
72 | }
73 | }
74 |
75 | func PrntFunctionMaker(boolcap bool, tab, strbeg, strend, arrbeg, arrend, objbeg, objend, keybeg, keyend string) interface{} {
76 | var vals func(interface{}, ...int) string
77 | var tabs func(int) string
78 |
79 | arrmid, objmid, newline := ",", ",", "\n"
80 |
81 | tabs = func(level int) string {
82 | str := ""
83 |
84 | for i := 0; i < level; i++ {
85 | str += tab
86 | }
87 |
88 | return str
89 | }
90 |
91 | vals = func(data interface{}, level ...int) string {
92 | typ, lev := reflect.TypeOf(data).String(), 1
93 |
94 | if len(level) == 1 {
95 | lev = level[0]
96 | }
97 |
98 | if typ == "bool" {
99 | str := strconv.FormatBool(data.(bool))
100 |
101 | if boolcap {
102 | str = inflect.Capitalize(str)
103 | }
104 |
105 | return str
106 | }
107 |
108 | if typ == "string" {
109 | return strbeg + data.(string) + strend
110 | }
111 |
112 | if typ == "int" {
113 | return strconv.Itoa(data.(int))
114 | }
115 |
116 | if typ == "float64" {
117 | return strconv.FormatFloat(data.(float64), 'f', -1, 64)
118 | }
119 |
120 | if typ == "[]interface {}" {
121 | str := arrbeg
122 |
123 | for _, v := range data.([]interface{}) {
124 | str += newline + tabs(lev) + vals(v, lev+1) + arrmid
125 | }
126 |
127 | return str[0:len(str)-len(arrmid)] + newline + tabs(lev-1) + arrend
128 | }
129 |
130 | if typ == "map[string]interface {}" {
131 | str := objbeg
132 |
133 | for k, v := range data.(map[string]interface{}) {
134 | str += newline + tabs(lev) + keybeg + k + keyend + vals(v, lev+1) + objmid
135 | }
136 |
137 | return str[0:len(str)-len(objmid)] + newline + tabs(lev-1) + objend
138 | }
139 |
140 | return ""
141 | }
142 |
143 | return func(api interface{}, doc map[string]DocParam, sep string, notLast bool) string {
144 | str, typ := "", reflect.TypeOf(api).String()
145 |
146 | if typ == "[]string" {
147 | for _, v := range api.([]string) {
148 | str += vals(doc[v].Value) + sep
149 | }
150 | } else if typ == "[]alpaca.ApiParam" {
151 | for _, v := range api.([]ApiParam) {
152 | if v.Required {
153 | str += vals(doc[v.Name].Value) + sep
154 | }
155 | }
156 | } else {
157 | return str
158 | }
159 |
160 | if str != "" && !notLast {
161 | return str[0 : len(str)-len(sep)]
162 | }
163 |
164 | return str
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/templates/ruby/lib/http_client.rb:
--------------------------------------------------------------------------------
1 | require "{{call .Fnc.underscore .Pkg.Name}}/http_client/auth_handler"
2 | require "{{call .Fnc.underscore .Pkg.Name}}/http_client/error_handler"
3 | require "{{call .Fnc.underscore .Pkg.Name}}/http_client/request_handler"
4 | require "{{call .Fnc.underscore .Pkg.Name}}/http_client/response"
5 | require "{{call .Fnc.underscore .Pkg.Name}}/http_client/response_handler"
6 |
7 | module {{call .Fnc.camelize .Pkg.Name}}
8 |
9 | module HttpClient
10 |
11 | # Main HttpClient which is used by Api classes
12 | class HttpClient
13 |
14 | attr_accessor :options, :headers
15 |
16 | def initialize({{if .Api.BaseAsArg}}base_url, {{end}}auth = {}, options = {})
17 | {{if .Api.Authorization.Oauth}}
18 | if auth.is_a?(String)
19 | auth = { :access_token => auth }
20 | end
21 | {{else}}{{if .Api.Authorization.Header}}
22 | if auth.is_a?(String)
23 | auth = { :http_header => auth }
24 | end
25 | {{end}}{{end}}
26 | @options = {
27 | :base => {{if .Api.BaseAsArg}}base_url{{else}}"{{.Api.Base}}"{{end}},{{with .Api.Version}}
28 | :api_version => "{{.}}",{{end}}
29 | :user_agent => "alpaca/{{.Version}} (https://github.com/pksunkara/alpaca)"
30 | }
31 |
32 | @options.update(options)
33 |
34 | @headers = {
35 | "user-agent" => @options[:user_agent]
36 | }
37 |
38 | if @options.has_key?(:headers)
39 | @headers.update(Hash[@options[:headers].map { |k, v| [k.downcase, v] }])
40 | @options.delete(:headers)
41 | end
42 | {{if .Api.NoVerifySSL}}
43 | @conn_options = {
44 | :ssl => { :verify => false }
45 | }
46 |
47 | @client = Faraday.new(@options[:base], @conn_options) do |conn|
48 | {{else}}
49 | @client = Faraday.new(@options[:base]) do |conn|
50 | {{end}} conn.use({{call .Fnc.camelize .Pkg.Name}}::HttpClient::AuthHandler, auth)
51 | conn.use({{call .Fnc.camelize .Pkg.Name}}::HttpClient::ErrorHandler)
52 |
53 | conn.adapter(Faraday.default_adapter)
54 | end
55 | end
56 |
57 | def get(path, params = {}, options = {})
58 | request(path, nil, "get", options.merge({ :query => params }))
59 | end
60 |
61 | def post(path, body = {}, options = {})
62 | request(path, body, "post", options)
63 | end
64 |
65 | def patch(path, body = {}, options = {})
66 | request(path, body, "patch", options)
67 | end
68 |
69 | def delete(path, body = {}, options = {})
70 | request(path, body, "delete", options)
71 | end
72 |
73 | def put(path, body = {}, options = {})
74 | request(path, body, "put", options)
75 | end
76 |
77 | # Intermediate function which does three main things
78 | #
79 | # - Transforms the body of request into correct format
80 | # - Creates the requests with give parameters
81 | # - Returns response body after parsing it into correct format
82 | def request(path, body, method, options)
83 | options = @options.merge(options)
84 |
85 | options[:headers] = options[:headers] || {}
86 | options[:headers] = @headers.merge(Hash[options[:headers].map { |k, v| [k.downcase, v] }])
87 |
88 | options[:body] = body
89 |
90 | if method != "get"
91 | options[:body] = options[:body] || {}
92 | options = set_body(options)
93 | end
94 |
95 | response = create_request(method, path, options)
96 |
97 | body = get_body(response)
98 |
99 | {{call .Fnc.camelize .Pkg.Name}}::HttpClient::Response.new(body, response.status, response.headers)
100 | end
101 |
102 | # Creating a request with the given arguments
103 | #
104 | # If api_version is set, appends it immediately after host
105 | def create_request(method, path, options)
106 | version = options.has_key?(:api_version) ? "/#{options[:api_version]}" : ""
107 | {{if .Api.Response.Suffix}}
108 | # Adds a suffix (ex: ".html", ".json") to url
109 | suffix = options.has_key?(:response_type) ? options[:response_type] : "{{.Api.Response.Formats.Default}}"
110 | path = "#{path}.#{suffix}"
111 | {{end}}
112 | path = "#{version}#{path}"
113 |
114 | instance_eval <<-RUBY, __FILE__, __LINE__ + 1
115 | @client.#{method}(path) do |req|
116 | req.body = options[:body]
117 | req.headers.update(options[:headers])
118 | req.params.update(options[:query]) if options[:query]
119 | end
120 | RUBY
121 | end
122 |
123 | # Get response body in correct format
124 | def get_body(response)
125 | {{call .Fnc.camelize .Pkg.Name}}::HttpClient::ResponseHandler.get_body(response)
126 | end
127 |
128 | # Set request body in correct format
129 | def set_body(options)
130 | {{call .Fnc.camelize .Pkg.Name}}::HttpClient::RequestHandler.set_body(options)
131 | end
132 |
133 | end
134 |
135 | end
136 |
137 | end
138 |
--------------------------------------------------------------------------------
/templates/python/lib/http_client/__init__.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import copy
3 |
4 | try:
5 | import urlparse
6 | except ImportError:
7 | import urllib.parse as urlparse
8 |
9 | from .auth_handler import AuthHandler
10 | from .error_handler import ErrorHandler
11 | from .request_handler import RequestHandler
12 | from .response import Response
13 | from .response_handler import ResponseHandler
14 |
15 |
16 | class HttpClient(object):
17 |
18 | """Main HttpClient which is used by API classes"""
19 |
20 | def __init__(self, {{if .Api.BaseAsArg}}base_url, {{end}}auth, options):
21 | {{if .Api.Authorization.Oauth}}
22 | if isinstance(auth, str):
23 | auth = {'access_token': auth}
24 | {{else}}{{if .Api.Authorization.Header}}
25 | if isinstance(auth, str):
26 | auth = {'http_header': auth}
27 | {{end}}{{end}}
28 | self.options = {
29 | 'base': {{if .Api.BaseAsArg}}base_url{{else}}'{{.Api.Base}}'{{end}},{{with .Api.Version}}
30 | 'api_version': '{{.}}',{{end}}
31 | 'user_agent': 'alpaca/{{.Version}} (https://github.com/pksunkara/alpaca)'
32 | }
33 |
34 | self.options.update(options)
35 |
36 | self.base = self.options['base']
37 |
38 | self.headers = {
39 | 'user-agent': self.options['user_agent']
40 | }
41 |
42 | if 'headers' in self.options:
43 | self.headers.update(self.dict_key_lower(self.options['headers']))
44 | del self.options['headers']
45 |
46 | self.auth = AuthHandler(auth)
47 |
48 | def get(self, path, params={}, options={}):
49 | options.update({'query': params})
50 | return self.request(path, None, 'get', options)
51 |
52 | def post(self, path, body={}, options={}):
53 | return self.request(path, body, 'post', options)
54 |
55 | def patch(self, path, body={}, options={}):
56 | return self.request(path, body, 'patch', options)
57 |
58 | def delete(self, path, body={}, options={}):
59 | return self.request(path, body, 'delete', options)
60 |
61 | def put(self, path, body={}, options={}):
62 | return self.request(path, body, 'put', options)
63 |
64 | def request(self, path, body, method, options):
65 | """Intermediate function which does three main things
66 |
67 | - Transforms the body of request into correct format
68 | - Creates the requests with given parameters
69 | - Returns response body after parsing it into correct format
70 | """
71 | kwargs = copy.deepcopy(self.options)
72 | kwargs.update(options)
73 |
74 | kwargs['headers'] = copy.deepcopy(self.headers)
75 |
76 | if 'headers' in options:
77 | kwargs['headers'].update(self.dict_key_lower(options['headers']))
78 |
79 | kwargs['data'] = body
80 | kwargs['allow_redirects'] = True
81 |
82 | kwargs['params'] = kwargs['query'] if 'query' in kwargs else {}
83 |
84 | if 'query' in kwargs:
85 | del kwargs['query']
86 |
87 | if 'body' in kwargs:
88 | del kwargs['body']
89 |
90 | del kwargs['base']
91 | del kwargs['user_agent']
92 | {{if .Api.NoVerifySSL}}
93 | kwargs['verify'] = False
94 | {{end}}
95 | if method != 'get':
96 | kwargs = self.set_body(kwargs)
97 |
98 | kwargs['hooks'] = dict(response=ErrorHandler.check_error)
99 |
100 | kwargs = self.auth.set(kwargs)
101 |
102 | response = self.create_request(method, path, kwargs)
103 |
104 | return Response(
105 | self.get_body(response), response.status_code, response.headers
106 | )
107 |
108 | def create_request(self, method, path, options):
109 | """Creating a request with the given arguments
110 |
111 | If api_version is set, appends it immediately after host
112 | """
113 | version = '/' + options['api_version'] if 'api_version' in options else ''
114 | {{if .Api.Response.Suffix}}
115 | # Adds a suffix (ex: ".html", ".json") to url
116 | suffix = options['response_type'] if 'response_type' in options else '{{.Api.Response.Formats.Default}}'
117 | path = path + '.' + suffix
118 | {{end}}
119 | path = urlparse.urljoin(self.base, version + path)
120 |
121 | if 'api_version' in options:
122 | del options['api_version']
123 |
124 | if 'response_type' in options:
125 | del options['response_type']
126 |
127 | return requests.request(method, path, **options)
128 |
129 | def get_body(self, response):
130 | """Get response body in correct format"""
131 | return ResponseHandler.get_body(response)
132 |
133 | def set_body(self, request):
134 | """Set request body in correct format"""
135 | return RequestHandler.set_body(request)
136 |
137 | def dict_key_lower(self, dic):
138 | """Make dict keys all lower case"""
139 | return dict(zip(map(self.key_lower, dic.keys()), dic.values()))
140 |
141 | def key_lower(self, key):
142 | """Make a function for lower case"""
143 | return key.lower()
144 |
--------------------------------------------------------------------------------
/templates/node/lib/http_client/index.js:
--------------------------------------------------------------------------------
1 | var url = require('url')
2 | , request = require('request');
3 |
4 | var client = module.exports;
5 |
6 | client.AuthHandler = require('./auth_handler');
7 | client.ErrorHandler = require('./error_handler');
8 |
9 | client.RequestHandler = require('./request_handler');
10 | client.ResponseHandler = require('./response_handler');
11 |
12 | client.Response = require('./response.js');
13 |
14 | /**
15 | * Main HttpClient which is used by Api classes
16 | */
17 | client.HttpClient = function ({{if .Api.BaseAsArg}}baseUrl, {{end}}auth, options) {
18 | if (!options) {
19 | options = {};
20 | }
21 |
22 | if (!auth) {
23 | auth = {};
24 | }
25 |
26 | {{if .Api.Authorization.Oauth}}
27 | if (typeof auth === 'string') {
28 | auth = { 'access_token': auth };
29 | }
30 | {{else}}{{if .Api.Authorization.Header}}
31 | if (typeof auth === 'string') {
32 | auth = { 'http_header': auth };
33 | }
34 | {{end}}{{end}}
35 | this.options = {
36 | 'base': {{if .Api.BaseAsArg}}baseUrl{{else}}'{{.Api.Base}}'{{end}},{{with .Api.Version}}
37 | 'api_version': '{{.}}',{{end}}
38 | 'user_agent': 'alpaca/{{.Version}} (https://github.com/pksunkara/alpaca)'
39 | };
40 |
41 | for (var key in options) {
42 | this.options[key] = options[key];
43 | }
44 |
45 | this.base = this.options.base;
46 |
47 | this.headers = {
48 | 'user-agent': this.options.user_agent
49 | };
50 |
51 | if (this.options.headers) {
52 | for (key in this.options.headers) {
53 | this.headers[key.toLowerCase()] = this.options.headers[key];
54 | }
55 |
56 | delete this.options.headers;
57 | }
58 |
59 | this.auth = new client.AuthHandler(auth);
60 |
61 | return this;
62 | };
63 |
64 | client.HttpClient.prototype.get = function (path, params, options, callback) {
65 | options.query = params;
66 |
67 | this.request(path, {}, 'GET', options, callback);
68 | };
69 |
70 | client.HttpClient.prototype.post = function (path, body, options, callback) {
71 | this.request(path, body, 'POST', options, callback);
72 | };
73 |
74 | client.HttpClient.prototype.patch = function (path, body, options, callback) {
75 | this.request(path, body, 'PATCH', options, callback);
76 | };
77 |
78 | client.HttpClient.prototype.delete = function (path, body, options, callback) {
79 | this.request(path, body, 'DELETE', options, callback);
80 | };
81 |
82 | client.HttpClient.prototype.put = function (path, body, options, callback) {
83 | this.request(path, body, 'PUT', options, callback);
84 | };
85 |
86 | /**
87 | * Intermediate function which does three main things
88 | *
89 | * - Transforms the body of request into correct format
90 | * - Creates the requests with give parameters
91 | * - Returns response body after parsing it into correct format
92 | */
93 | client.HttpClient.prototype.request = function (path, body, method, options, callback) {
94 | var headers = {}, self = this;
95 |
96 | for (var key in this.options) {
97 | if (!options[key]) {
98 | options[key] = this.options[key];
99 | }
100 | }
101 |
102 | if (options.headers) {
103 | headers = options.headers;
104 | delete options.headers;
105 | }
106 |
107 | for (key in headers) {
108 | var lowerKey = key.toLowerCase();
109 |
110 | if (key !== lowerKey) {
111 | headers[lowerKey] = headers[key];
112 | delete headers[key];
113 | }
114 | }
115 |
116 | for (key in this.headers) {
117 | if (!headers[key]) {
118 | headers[key] = this.headers[key];
119 | }
120 | }
121 |
122 | var reqobj = {
123 | 'url': path,
124 | 'qs': options.query || {},
125 | 'method': method,
126 | 'headers': headers
127 | };
128 |
129 | delete options.query;
130 | delete options.body;
131 |
132 | delete options.base;
133 | delete options.user_agent;
134 | {{if .Api.NoVerifySSL}}
135 | reqobj['strictSSL'] = false;
136 | {{end}}
137 | if (method !== 'GET') {
138 | reqobj = this.setBody(reqobj, body, options);
139 | }
140 |
141 | this.auth.set(reqobj, function (err, reqobj) {
142 | if (err) {
143 | return callback(err);
144 | }
145 |
146 | self.createRequest(reqobj, options, function(err, response, body) {
147 | if (err) {
148 | return callback(err);
149 | }
150 |
151 | self.getBody(response, body, function(err, response, body) {
152 | if (err) {
153 | return callback(err);
154 | }
155 |
156 | client.ErrorHandler(response, body, function(err, response, body) {
157 | if (err) {
158 | return callback(err);
159 | }
160 |
161 | callback(null, new client.Response(body, response.statusCode, response.headers));
162 | });
163 | });
164 | });
165 | });
166 | };
167 |
168 | /**
169 | * Creating a request with the given arguments
170 | *
171 | * If api_version is set, appends it immediately after host
172 | */
173 | client.HttpClient.prototype.createRequest = function (reqobj, options, callback) {
174 | var version = (options.api_version ? '/' + options.api_version : '');
175 | {{if .Api.Response.Suffix}}
176 | // Adds a suffix (ex: ".html", ".json") to url
177 | var suffix = (options.response_type ? options.response_type : '{{.Api.Response.Formats.Default}}');
178 | reqobj.url = reqobj.url + '.' + suffix;
179 | {{end}}
180 | reqobj.url = url.resolve(this.base, version + reqobj.url);
181 |
182 | request(reqobj, callback);
183 | };
184 |
185 | /**
186 | * Get response body in correct format
187 | */
188 | client.HttpClient.prototype.getBody = function (response, body, callback) {
189 | client.ResponseHandler.getBody(response, body, callback);
190 | };
191 |
192 | /**
193 | * Set request body in correct format
194 | */
195 | client.HttpClient.prototype.setBody = function (request, body, options) {
196 | return client.RequestHandler.setBody(request, body, options);
197 | };
198 |
--------------------------------------------------------------------------------
/examples/buffer/doc.json:
--------------------------------------------------------------------------------
1 | {
2 | "info": {
3 | "title": "Information",
4 | "desc": "Returns api instance to get auxilary information about Buffer useful when creating your app.",
5 | "functions": {
6 | "show": {
7 | "title": "Services and configuration",
8 | "desc": "Returns an object with the current configuration that Buffer is using, including supported services, their icons and the varying limits of character and schedules."
9 | }
10 | }
11 | },
12 | "user": {
13 | "title": "Authenticated user",
14 | "desc": "Returns authenticated user api instance.",
15 | "functions": {
16 | "show": {
17 | "title": "User information",
18 | "desc": "Returns information about the authenticated user."
19 | },
20 | "profiles": {
21 | "title": "List of user's social profiles",
22 | "desc": "Returns an array of social media profiles connected to the authenticated users account."
23 | },
24 | "create_update": {
25 | "title": "Create a social update",
26 | "desc": "Create one or more new status updates.",
27 | "params": {
28 | "text": {
29 | "desc": "The status update text.",
30 | "value": "This is an example update"
31 | },
32 | "profile_ids": {
33 | "desc": "An array of profile id's that the status update should be sent to. Invalid profile_id's will be silently ignored.",
34 | "value": ["4eb854340acb04e870000010", "4eb9276e0acb04bb81000067"]
35 | }
36 | }
37 | }
38 | }
39 | },
40 | "link": {
41 | "title": "Links",
42 | "desc": "Returns api instance to get information about links shared through Buffer.",
43 | "functions": {
44 | "shares": {
45 | "title": "Amount of link shares",
46 | "desc": "Returns an object with a the numbers of shares a link has had using Buffer.",
47 | "params": {
48 | "url": {
49 | "desc": "URL of the page for which the number of shares is requested.",
50 | "value": "http://bufferapp.com"
51 | }
52 | }
53 | }
54 | }
55 | },
56 | "profile": {
57 | "title": "Social profiles",
58 | "desc": "Returns a social media profile api instance.",
59 | "args": {
60 | "id": {
61 | "desc": "Identifier of a social media profile",
62 | "value": "519fc3ca4d5e93901900002f"
63 | }
64 | },
65 | "functions": {
66 | "show": {
67 | "title": "Get this social profile",
68 | "desc": "Returns details of the single specified social media profile."
69 | },
70 | "pending": {
71 | "title": "List profile's pending updates",
72 | "desc": "Returns an array of updates that are currently in the buffer for an individual social media profile."
73 | },
74 | "sent": {
75 | "title": "List profile's sent updates",
76 | "desc": "Returns an array of updates that have been sent from the buffer for an individual social media profile."
77 | },
78 | "reorder": {
79 | "title": "Edit profile's updates order",
80 | "desc": "Edit the order at which statuses for the specified social media profile will be sent out of the buffer.",
81 | "params": {
82 | "order": {
83 | "desc": "An ordered array of status update id's. This can be a partial array in combination with the offset parameter or a full array of every update in the profiles Buffer.",
84 | "value": ["4eb854340acb04e870000010", "4eb9276e0acb04bb81000067", "4eb2567e0ade04ba51000001"]
85 | }
86 | }
87 | },
88 | "shuffle": {
89 | "title": "Shuffle profile's updates",
90 | "desc": "Randomize the order at which statuses for the specified social media profile will be sent out of the buffer."
91 | }
92 | }
93 | },
94 | "schedule": {
95 | "title": "Posting schedules",
96 | "desc": "Returns scheduling api instance for social media profile.",
97 | "args": {
98 | "id": {
99 | "desc": "Identifier of a social media profile",
100 | "value": "519fc3ca4d5e93901900002f"
101 | }
102 | },
103 | "functions": {
104 | "list": {
105 | "title": "Get profile's posting schedules",
106 | "desc": "Returns details of the posting schedules associated with a social media profile."
107 | },
108 | "update": {
109 | "title": "Update profile's posting schedules",
110 | "desc": "Set the posting schedules for the specified social media profile.",
111 | "params": {
112 | "schedules": {
113 | "desc": "Each item in the array is an individual posting schedule which consists of days and times to match the format return by the above method.",
114 | "value": [{
115 | "days": ["mon", "tue", "thu"],
116 | "times": ["12:45", "15:30", "17:43"]
117 | }]
118 | }
119 | }
120 | }
121 | }
122 | },
123 | "update": {
124 | "title": "Social updates",
125 | "desc": "Returns a social media update api instance.",
126 | "args": {
127 | "id": {
128 | "desc": "Identifier of a social media update",
129 | "value": "4eb8565e0acb04bb82000004"
130 | }
131 | },
132 | "functions": {
133 | "show": {
134 | "title": "Get this social update",
135 | "desc": "Returns a single social media update."
136 | },
137 | "interactions": {
138 | "title": "List interactions of the update",
139 | "desc": "Returns the detailed information on individual interactions with the social media update such as favorites, retweets and likes."
140 | },
141 | "update": {
142 | "title": "Edit this update",
143 | "desc": "Edit an existing, individual status update.",
144 | "params": {
145 | "text": {
146 | "desc": "The status update text.",
147 | "value": "This is an edited update"
148 | }
149 | }
150 | },
151 | "share": {
152 | "title": "Share this update",
153 | "desc": "Immediately shares a single pending update and recalculates times for updates remaining in the queue."
154 | },
155 | "destroy": {
156 | "title": "Delete this update",
157 | "desc": "Permanently delete an existing status update."
158 | },
159 | "top": {
160 | "title": "Move this update to top",
161 | "desc": "Move an existing status update to the top of the queue and recalculate times for all updates in the queue. Returns the update with its new posting time."
162 | }
163 | }
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/templates/php/lib/HttpClient/HttpClient.php:
--------------------------------------------------------------------------------
1 | '{{.Api.Base}}',{{with .Api.Version}}
22 | 'api_version' => '{{.}}',{{end}}
23 | 'user_agent' => 'alpaca/{{.Version}} (https://github.com/pksunkara/alpaca)'
24 | );
25 |
26 | protected $headers = array();
27 |
28 | public function __construct({{if .Api.BaseAsArg}}$baseUrl, {{end}}$auth = array(), array $options = array())
29 | {
30 | {{if .Api.BaseAsArg}} $this->options['base'] = $baseUrl;
31 | {{end}}{{if .Api.Authorization.Oauth}}
32 | if (gettype($auth) == 'string') {
33 | $auth = array('access_token' => $auth);
34 | }
35 | {{else}}{{if .Api.Authorization.Header}}
36 | if (gettype($auth) == 'string') {
37 | $auth = array('http_header' => $auth);
38 | }
39 | {{end}}{{end}}
40 | $this->options = array_merge($this->options, $options);
41 |
42 | $this->headers = array(
43 | 'user-agent' => $this->options['user_agent'],
44 | );
45 |
46 | if (isset($this->options['headers'])) {
47 | $this->headers = array_merge($this->headers, array_change_key_case($this->options['headers']));
48 | unset($this->options['headers']);
49 | }
50 |
51 | $client = new GuzzleClient($this->options['base'], $this->options);
52 | $this->client = $client;
53 |
54 | $listener = array(new ErrorHandler(), 'onRequestError');
55 | $this->client->getEventDispatcher()->addListener('request.error', $listener);
56 |
57 | if (!empty($auth)) {
58 | $listener = array(new AuthHandler($auth), 'onRequestBeforeSend');
59 | $this->client->getEventDispatcher()->addListener('request.before_send', $listener);
60 | }
61 | }
62 |
63 | public function get($path, array $params = array(), array $options = array())
64 | {
65 | return $this->request($path, null, 'GET', array_merge($options, array('query' => $params)));
66 | }
67 |
68 | public function post($path, $body, array $options = array())
69 | {
70 | return $this->request($path, $body, 'POST', $options);
71 | }
72 |
73 | public function patch($path, $body, array $options = array())
74 | {
75 | return $this->request($path, $body, 'PATCH', $options);
76 | }
77 |
78 | public function delete($path, $body, array $options = array())
79 | {
80 | return $this->request($path, $body, 'DELETE', $options);
81 | }
82 |
83 | public function put($path, $body, array $options = array())
84 | {
85 | return $this->request($path, $body, 'PUT', $options);
86 | }
87 |
88 | /**
89 | * Intermediate function which does three main things
90 | *
91 | * - Transforms the body of request into correct format
92 | * - Creates the requests with give parameters
93 | * - Returns response body after parsing it into correct format
94 | */
95 | public function request($path, $body = null, $httpMethod = 'GET', array $options = array())
96 | {
97 | $headers = array();
98 |
99 | $options = array_merge($this->options, $options);
100 |
101 | if (isset($options['headers'])) {
102 | $headers = $options['headers'];
103 | unset($options['headers']);
104 | }
105 |
106 | $headers = array_merge($this->headers, array_change_key_case($headers));
107 |
108 | unset($options['body']);
109 |
110 | unset($options['base']);
111 | unset($options['user_agent']);
112 | {{if .Api.NoVerifySSL}}
113 | $options['verify'] = false;
114 | {{end}}
115 | $request = $this->createRequest($httpMethod, $path, null, $headers, $options);
116 |
117 | if ($httpMethod != 'GET') {
118 | $request = $this->setBody($request, $body, $options);
119 | }
120 |
121 | try {
122 | $response = $this->client->send($request);
123 | } catch (\LogicException $e) {
124 | throw new \ErrorException($e->getMessage());
125 | } catch (\RuntimeException $e) {
126 | throw new \RuntimeException($e->getMessage());
127 | }
128 |
129 | return new Response($this->getBody($response), $response->getStatusCode(), $response->getHeaders());
130 | }
131 |
132 | /**
133 | * Creating a request with the given arguments
134 | *
135 | * If api_version is set, appends it immediately after host
136 | */
137 | public function createRequest($httpMethod, $path, $body = null, array $headers = array(), array $options = array())
138 | {
139 | $version = (isset($options['api_version']) ? "/".$options['api_version'] : "");
140 | {{if .Api.Response.Suffix}}
141 | // Adds a suffix (ex: ".html", ".json") to url
142 | $suffix = (isset($options['response_type']) ? $options['response_type'] : "{{.Api.Response.Formats.Default}}");
143 | $path = $path.".".$suffix;
144 | {{end}}
145 | $path = $version.$path;
146 |
147 | return $this->client->createRequest($httpMethod, $path, $headers, $body, $options);
148 | }
149 |
150 | /**
151 | * Get response body in correct format
152 | */
153 | public function getBody($response)
154 | {
155 | return ResponseHandler::getBody($response);
156 | }
157 |
158 | /**
159 | * Set request body in correct format
160 | */
161 | public function setBody(RequestInterface $request, $body, $options)
162 | {
163 | return RequestHandler::setBody($request, $body, $options);
164 | }
165 | }
166 |
--------------------------------------------------------------------------------
/templates/python/readme.md:
--------------------------------------------------------------------------------
1 | # {{.Pkg.Git.Name}}-python
2 |
3 | {{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for python
4 |
5 | __This library is generated by [alpaca](https://github.com/pksunkara/alpaca)__
6 |
7 | ## Installation
8 |
9 | Make sure you have [pip](https://pypi.python.org/pypi/pip) installed
10 |
11 | ```bash
12 | $ pip install {{.Pkg.Package}}
13 | ```
14 |
15 | #### Versions
16 |
17 | Works with [ 2.6 / 2.7 / 3.2 / 3.3 ]
18 |
19 | ## Usage
20 |
21 | ```python
22 | import {{call .Fnc.underscore .Pkg.Name}}
23 |
24 | # Then we instantiate a client (as shown below)
25 | ```
26 |
27 | ### Build a client
28 | {{if .Api.Authorization.NeedAuth}}
29 | __Using this api without authentication gives an error__
30 | {{else}}
31 | ##### Without any authentication
32 |
33 | ```python
34 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}'{{end}})
35 |
36 | # If you need to send options
37 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{}, client_options)
38 | ```
39 | {{end}}{{if .Api.Authorization.Basic}}
40 | ##### Basic authentication
41 |
42 | ```python
43 | auth = { 'username': 'pksunkara', 'password': 'password' }
44 |
45 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}auth, client_options)
46 | ```
47 | {{end}}{{if .Api.Authorization.Header}}
48 | ##### Authorization header token
49 |
50 | ```python
51 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{{if .Api.Authorization.Oauth}}{'http_header': '1a2b3'}{{else}}'1a2b3'{{end}}, client_options)
52 | ```
53 | {{end}}{{if .Api.Authorization.Oauth}}
54 | ##### Oauth access token
55 |
56 | ```python
57 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}'1a2b3', client_options)
58 | ```
59 |
60 | ##### Oauth client secret
61 |
62 | ```python
63 | auth = { 'client_id': '09a8b7', 'client_secret': '1a2b3' }
64 |
65 | client = {{call .Fnc.underscore .Pkg.Name}}.Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}auth, client_options)
66 | ```
67 | {{end}}
68 | ### Client Options
69 |
70 | The following options are available while instantiating a client:
71 |
72 | * __base__: Base url for the api
73 | * __api_version__: Default version of the api (to be used in url)
74 | * __user_agent__: Default user-agent for all requests
75 | * __headers__: Default headers for all requests
76 | * __request_type__: Default format of the request body{{if .Api.Response.Suffix}}
77 | * __response_type__: Default format of the response (to be used in url suffix){{end}}
78 |
79 | ### Response information
80 |
81 | __All the callbacks provided to an api call will receive the response as shown below__
82 |
83 | ```python
84 | response = client.klass('args').method('args', method_options)
85 |
86 | response.code
87 | # >>> 200
88 |
89 | response.headers
90 | # >>> {'x-server': 'apache'}
91 | ```
92 | {{if .Api.Response.Formats.Html}}
93 | ##### HTML/TEXT response
94 |
95 | When the response sent by server is either __html__ or __text__, it is not changed in any way
96 |
97 | ```python
98 | response.body
99 | # >>> 'The username is pksunkara!'
100 | ```
101 | {{end}}{{if .Api.Response.Formats.Json}}
102 | ##### JSON response
103 |
104 | When the response sent by server is __json__, it is decoded into a dict
105 |
106 | ```python
107 | response.body
108 | # >>> {'user': 'pksunkara'}
109 | ```
110 | {{end}}
111 | ### Method Options
112 |
113 | The following options are available while calling a method of an api:
114 |
115 | * __api_version__: Version of the api (to be used in url)
116 | * __headers__: Headers for the request
117 | * __query__: Query parameters for the url
118 | * __body__: Body of the request
119 | * __request_type__: Format of the request body{{if .Api.Response.Suffix}}
120 | * __response_type__: Format of the response (to be used in url suffix){{end}}
121 |
122 | ### Request body information
123 |
124 | Set __request_type__ in options to modify the body accordingly
125 |
126 | ##### RAW request
127 |
128 | When the value is set to __raw__, don't modify the body at all.
129 |
130 | ```python
131 | body = 'username=pksunkara'
132 | # >>> 'username=pksunkara'
133 | ```
134 | {{if .Api.Request.Formats.Form}}
135 | ##### FORM request
136 |
137 | When the value is set to __form__, urlencode the body.
138 |
139 | ```python
140 | body = {'user': 'pksunkara'}
141 | # >>> 'user=pksunkara'
142 | ```
143 | {{end}}{{if .Api.Request.Formats.Json}}
144 | ##### JSON request
145 |
146 | When the value is set to __json__, JSON encode the body.
147 |
148 | ```python
149 | body = {'user': 'pksunkara'}
150 | # >>> '{"user": "pksunkara"}'
151 | ```
152 | {{end}}{{with $data := .}}{{range .Api.Classes}}
153 | ### {{(index $data.Doc .Name).Title}} api
154 |
155 | {{(index $data.Doc .Name).Desc}}{{with .Args}}
156 |
157 | The following arguments are required:
158 | {{end}}{{with $class := .}}{{range .Args}}
159 | * __{{.}}__: {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}
160 |
161 | ```python
162 | {{call $data.Fnc.underscore $class.Name}} = client.{{call $data.Fnc.underscore $class.Name}}({{call $data.Fnc.prnt.python .Args ((index $data.Doc $class.Name).Args) ", " false}})
163 | ```
164 | {{range $class.Functions}}
165 | ##### {{(index ((index $data.Doc $class.Name).Functions) .Name).Title}} ({{call $data.Fnc.upper (or .Method "get")}} {{.Path}})
166 |
167 | {{(index ((index $data.Doc $class.Name).Functions) .Name).Desc}}{{with .Params}}
168 |
169 | The following arguments are required:
170 | {{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
171 | * __{{.Name}}__: {{(index ((index ((index $data.Doc $class.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
172 |
173 | ```python
174 | response = {{call $data.Fnc.underscore $class.Name}}.{{call $data.Fnc.underscore .Name}}({{call $data.Fnc.prnt.python .Params ((index ((index $data.Doc $class.Name).Functions) .Name).Params) ", " true}}options)
175 | ```
176 | {{end}}{{end}}{{end}}{{end}}
177 | ## Contributors
178 | Here is a list of [Contributors](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-python/contributors)
179 |
180 | ### TODO
181 |
182 | ## License
183 | {{.Pkg.License}}
184 |
185 | ## Bug Reports
186 | Report [here](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-python/issues).
187 |
188 | ## Contact
189 | {{.Pkg.Author.Name}} ({{.Pkg.Author.Email}})
190 |
--------------------------------------------------------------------------------
/templates/ruby/readme.md:
--------------------------------------------------------------------------------
1 | # {{.Pkg.Git.Name}}-ruby
2 |
3 | {{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for ruby
4 |
5 | __This library is generated by [alpaca](https://github.com/pksunkara/alpaca)__
6 |
7 | ## Installation
8 |
9 | Make sure you have [rubygems](https://rubygems.org) installed
10 |
11 | ```bash
12 | $ gem install {{.Pkg.Package}}
13 | ```
14 |
15 | #### Versions
16 |
17 | Works with [ 1.8.6 / 1.8.7 / 1.9.1 / 1.9.2 / 1.9.3 / 2.0.0 / 2.1.0 / 2.1.1 ]
18 |
19 | ## Usage
20 |
21 | ```ruby
22 | require "{{.Pkg.Package}}"
23 |
24 | # Then we instantiate a client (as shown below)
25 | ```
26 |
27 | ### Build a client
28 | {{if .Api.Authorization.NeedAuth}}
29 | __Using this api without authentication gives an error__
30 | {{else}}
31 | ##### Without any authentication
32 |
33 | ```ruby
34 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new{{if .Api.BaseAsArg}}('{{.Api.Base}}'){{end}}
35 |
36 | # If you need to send options
37 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{}, client_options)
38 | ```
39 | {{end}}{{if .Api.Authorization.Basic}}
40 | ##### Basic authentication
41 |
42 | ```ruby
43 | auth = { :username => 'pksunkara', :password => 'password' }
44 |
45 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}auth, client_options)
46 | ```
47 | {{end}}{{if .Api.Authorization.Header}}
48 | ##### Authorization header token
49 |
50 | ```ruby
51 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{{if .Api.Authorization.Oauth}}{:http_header => '1a2b3'}{{else}}'1a2b3'{{end}}, client_options)
52 | ```
53 | {{end}}{{if .Api.Authorization.Oauth}}
54 | ##### Oauth access token
55 |
56 | ```ruby
57 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}'1a2b3', client_options)
58 | ```
59 |
60 | ##### Oauth client secret
61 |
62 | ```ruby
63 | auth = { :client_id => '09a8b7', :client_secret => '1a2b3' }
64 |
65 | client = {{call .Fnc.camelize .Pkg.Name}}::Client.new({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}auth, client_options)
66 | ```
67 | {{end}}
68 | ### Client Options
69 |
70 | The following options are available while instantiating a client:
71 |
72 | * __base__: Base url for the api
73 | * __api_version__: Default version of the api (to be used in url)
74 | * __user_agent__: Default user-agent for all requests
75 | * __headers__: Default headers for all requests
76 | * __request_type__: Default format of the request body{{if .Api.Response.Suffix}}
77 | * __response_type__: Default format of the response (to be used in url suffix){{end}}
78 |
79 | ### Response information
80 |
81 | __All the callbacks provided to an api call will receive the response as shown below__
82 |
83 | ```ruby
84 | response = client.klass('args').method('args', method_options)
85 |
86 | response.code
87 | # >>> 200
88 |
89 | response.headers
90 | # >>> {'x-server' => 'apache'}
91 | ```
92 | {{if .Api.Response.Formats.Html}}
93 | ##### HTML/TEXT response
94 |
95 | When the response sent by server is either __html__ or __text__, it is not changed in any way
96 |
97 | ```ruby
98 | response.body
99 | # >>> 'The username is pksunkara!'
100 | ```
101 | {{end}}{{if .Api.Response.Formats.Json}}
102 | ##### JSON response
103 |
104 | When the response sent by server is __json__, it is decoded into a hash
105 |
106 | ```ruby
107 | response.body
108 | # >>> {'user' => 'pksunkara'}
109 | ```
110 | {{end}}
111 | ### Method Options
112 |
113 | The following options are available while calling a method of an api:
114 |
115 | * __api_version__: Version of the api (to be used in url)
116 | * __headers__: Headers for the request
117 | * __query__: Query parameters for the url
118 | * __body__: Body of the request
119 | * __request_type__: Format of the request body{{if .Api.Response.Suffix}}
120 | * __response_type__: Format of the response (to be used in url suffix){{end}}
121 |
122 | ### Request body information
123 |
124 | Set __request_type__ in options to modify the body accordingly
125 |
126 | ##### RAW request
127 |
128 | When the value is set to __raw__, don't modify the body at all.
129 |
130 | ```ruby
131 | body = 'username=pksunkara'
132 | # >>> 'username=pksunkara'
133 | ```
134 | {{if .Api.Request.Formats.Form}}
135 | ##### FORM request
136 |
137 | When the value is set to __form__, urlencode the body.
138 |
139 | ```ruby
140 | body = {'user' => 'pksunkara'}
141 | # >>> 'user=pksunkara'
142 | ```
143 | {{end}}{{if .Api.Request.Formats.Json}}
144 | ##### JSON request
145 |
146 | When the value is set to __json__, JSON encode the body.
147 |
148 | ```ruby
149 | body = {'user' => 'pksunkara'}
150 | # >>> '{"user": "pksunkara"}'
151 | ```
152 | {{end}}{{with $data := .}}{{range .Api.Classes}}
153 | ### {{(index $data.Doc .Name).Title}} api
154 |
155 | {{(index $data.Doc .Name).Desc}}{{with .Args}}
156 |
157 | The following arguments are required:
158 | {{end}}{{with $class := .}}{{range .Args}}
159 | * __{{.}}__: {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}
160 |
161 | ```ruby
162 | {{call $data.Fnc.underscore $class.Name}} = client.{{call $data.Fnc.underscore $class.Name}}({{call $data.Fnc.prnt.ruby .Args ((index $data.Doc $class.Name).Args) ", " false}})
163 | ```
164 | {{range $class.Functions}}
165 | ##### {{(index ((index $data.Doc $class.Name).Functions) .Name).Title}} ({{call $data.Fnc.upper (or .Method "get")}} {{.Path}})
166 |
167 | {{(index ((index $data.Doc $class.Name).Functions) .Name).Desc}}{{with .Params}}
168 |
169 | The following arguments are required:
170 | {{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
171 | * __{{.Name}}__: {{(index ((index ((index $data.Doc $class.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
172 |
173 | ```ruby
174 | response = {{call $data.Fnc.underscore $class.Name}}.{{call $data.Fnc.underscore .Name}}({{call $data.Fnc.prnt.ruby .Params ((index ((index $data.Doc $class.Name).Functions) .Name).Params) ", " true}}options)
175 | ```
176 | {{end}}{{end}}{{end}}{{end}}
177 | ## Contributors
178 | Here is a list of [Contributors](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-ruby/contributors)
179 |
180 | ### TODO
181 |
182 | ## License
183 | {{.Pkg.License}}
184 |
185 | ## Bug Reports
186 | Report [here](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-ruby/issues).
187 |
188 | ## Contact
189 | {{.Pkg.Author.Name}} ({{.Pkg.Author.Email}})
190 |
--------------------------------------------------------------------------------
/templates/node/readme.md:
--------------------------------------------------------------------------------
1 | # {{.Pkg.Git.Name}}-node
2 |
3 | {{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for node.js
4 |
5 | __This library is generated by [alpaca](https://github.com/pksunkara/alpaca)__
6 |
7 | ## Installation
8 |
9 | Make sure you have [npm](https://npmjs.org) installed.
10 |
11 | ```bash
12 | $ npm install {{.Pkg.Package}}
13 | ```
14 |
15 | #### Versions
16 |
17 | Works with [ 0.8 / 0.9 / 0.10 / 0.11 ]
18 |
19 | ## Usage
20 |
21 | ```js
22 | var {{call .Fnc.camelizeDownFirst .Pkg.Name}} = require('{{.Pkg.Package}}');
23 |
24 | // Then we instantiate a client (as shown below)
25 | ```
26 |
27 | ### Build a client
28 | {{if .Api.Authorization.NeedAuth}}
29 | __Using this api without authentication gives an error__
30 | {{else}}
31 | ##### Without any authentication
32 |
33 | ```js
34 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}'{{end}});
35 |
36 | // If you need to send options
37 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{}, clientOptions);
38 | ```
39 | {{end}}{{if .Api.Authorization.Basic}}
40 | ##### Basic authentication
41 |
42 | ```js
43 | var auth = { username: 'pksunkara', password: 'password' };
44 |
45 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}auth, clientOptions);
46 | ```
47 | {{end}}{{if .Api.Authorization.Header}}
48 | ##### Authorization header token
49 |
50 | ```js
51 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{{if .Api.Authorization.Oauth}}{ http_header: '1a2b3' }{{else}}'1a2b3'{{end}}, clientOptions);
52 | ```
53 | {{end}}{{if .Api.Authorization.Oauth}}
54 | ##### Oauth access token
55 |
56 | ```js
57 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}'1a2b3', clientOptions);
58 | ```
59 |
60 | ##### Oauth client secret
61 |
62 | ```js
63 | var client = {{call .Fnc.camelizeDownFirst .Pkg.Name}}.client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{
64 | client_id: '09a8b7',
65 | client_secret: '1a2b3'
66 | }, clientOptions);
67 | ```
68 | {{end}}
69 | ### Client Options
70 |
71 | The following options are available while instantiating a client:
72 |
73 | * __base__: Base url for the api
74 | * __api_version__: Default version of the api (to be used in url)
75 | * __user_agent__: Default user-agent for all requests
76 | * __headers__: Default headers for all requests
77 | * __request_type__: Default format of the request body{{if .Api.Response.Suffix}}
78 | * __response_type__: Default format of the response (to be used in url suffix){{end}}
79 |
80 | ### Response information
81 |
82 | __All the callbacks provided to an api call will receive the response as shown below__
83 |
84 | ```js
85 | // You can also omit the 'methodOptions' param below
86 | client.klass('args').method('args', methodOptions, function (err, response) {
87 | if (err) console.log(err);
88 |
89 | response.code;
90 | // >>> 200
91 |
92 | response.headers;
93 | // >>> {'x-server': 'apache'}
94 | }
95 | ```
96 | {{if .Api.Response.Formats.Html}}
97 | ##### HTML/TEXT response
98 |
99 | When the response sent by server is either __html__ or __text__, it is not changed in any way
100 |
101 | ```js
102 | response.body;
103 | // >>> 'The username is pksunkara!'
104 | ```
105 | {{end}}{{if .Api.Response.Formats.Json}}
106 | ##### JSON response
107 |
108 | When the response sent by server is __json__, it is decoded into a hash
109 |
110 | ```js
111 | response.body;
112 | // >>> {'user': 'pksunkara'}
113 | ```
114 | {{end}}
115 | ### Method Options
116 |
117 | The following options are available while calling a method of an api:
118 |
119 | * __api_version__: Version of the api (to be used in url)
120 | * __headers__: Headers for the request
121 | * __query__: Query parameters for the url
122 | * __body__: Body of the request
123 | * __request_type__: Format of the request body{{if .Api.Response.Suffix}}
124 | * __response_type__: Format of the response (to be used in url suffix){{end}}
125 |
126 | ### Request body information
127 |
128 | Set __request_type__ in options to modify the body accordingly
129 |
130 | ##### RAW request
131 |
132 | When the value is set to __raw__, don't modify the body at all.
133 |
134 | ```js
135 | body = 'username=pksunkara';
136 | // >>> 'username=pksunkara'
137 | ```
138 | {{if .Api.Request.Formats.Form}}
139 | ##### FORM request
140 |
141 | When the value is set to __form__, urlencode the body.
142 |
143 | ```js
144 | body = {'user': 'pksunkara'};
145 | // >>> 'user=pksunkara'
146 | ```
147 | {{end}}{{if .Api.Request.Formats.Json}}
148 | ##### JSON request
149 |
150 | When the value is set to __json__, JSON encode the body.
151 |
152 | ```js
153 | body = {'user': 'pksunkara'};
154 | // >>> '{"user": "pksunkara"}'
155 | ```
156 | {{end}}{{with $data := .}}{{range .Api.Classes}}
157 | ### {{(index $data.Doc .Name).Title}} api
158 |
159 | {{(index $data.Doc .Name).Desc}}{{with .Args}}
160 |
161 | The following arguments are required:
162 | {{end}}{{with $class := .}}{{range .Args}}
163 | * __{{.}}__: {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}
164 |
165 | ```js
166 | var {{call $data.Fnc.camelizeDownFirst $class.Name}} = client.{{call $data.Fnc.camelizeDownFirst $class.Name}}({{call $data.Fnc.prnt.node .Args ((index $data.Doc $class.Name).Args) ", " false}});
167 | ```
168 | {{range $class.Functions}}
169 | ##### {{(index ((index $data.Doc $class.Name).Functions) .Name).Title}} ({{call $data.Fnc.upper (or .Method "get")}} {{.Path}})
170 |
171 | {{(index ((index $data.Doc $class.Name).Functions) .Name).Desc}}{{with .Params}}
172 |
173 | The following arguments are required:
174 | {{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
175 | * __{{.Name}}__: {{(index ((index ((index $data.Doc $class.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
176 |
177 | ```js
178 | {{call $data.Fnc.camelizeDownFirst $class.Name}}.{{call $data.Fnc.camelizeDownFirst .Name}}({{call $data.Fnc.prnt.node .Params ((index ((index $data.Doc $class.Name).Functions) .Name).Params) ", " true}}options, callback);
179 | ```
180 | {{end}}{{end}}{{end}}{{end}}
181 | ## Contributors
182 | Here is a list of [Contributors](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-node/contributors)
183 |
184 | ### TODO
185 |
186 | ## License
187 | {{.Pkg.License}}
188 |
189 | ## Bug Reports
190 | Report [here](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-node/issues).
191 |
192 | ## Contact
193 | {{.Pkg.Author.Name}} ({{.Pkg.Author.Email}})
194 |
--------------------------------------------------------------------------------
/templates/php/readme.md:
--------------------------------------------------------------------------------
1 | # {{.Pkg.Git.Name}}-php
2 |
3 | {{if .Pkg.Official}}Official {{end}}{{.Pkg.Name}} API library client for PHP
4 |
5 | __This library is generated by [alpaca](https://github.com/pksunkara/alpaca)__
6 |
7 | ## Installation
8 |
9 | Make sure you have [composer](https://getcomposer.org) installed.
10 |
11 | Add the following to your composer.json
12 |
13 | ```js
14 | {
15 | "require": {
16 | "{{.Pkg.Php.Vendor}}/{{.Pkg.Package}}": "*"
17 | }
18 | }
19 | ```
20 |
21 | Update your dependencies
22 |
23 | ```bash
24 | $ php composer.phar update
25 | ```
26 |
27 | > This package follows the `PSR-0` convention names for its classes, which means you can easily integrate these classes loading in your own autoloader.
28 |
29 | #### Versions
30 |
31 | Works with [ 5.4 / 5.5 ]
32 |
33 | ## Usage
34 |
35 | ```php
36 | 'pksunkara', 'password' => 'password');
61 |
62 | $client = new {{call .Fnc.camelize .Pkg.Name}}\Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}$auth, $clientOptions);
63 | ```
64 | {{end}}{{if .Api.Authorization.Header}}
65 | ##### Authorization header token
66 |
67 | ```php
68 | $client = new {{call .Fnc.camelize .Pkg.Name}}\Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}{{if .Api.Authorization.Oauth}}array('http_header' => '1a2b3'){{else}}'1a2b3'{{end}}, $clientOptions);
69 | ```
70 | {{end}}{{if .Api.Authorization.Oauth}}
71 | ##### Oauth access token
72 |
73 | ```php
74 | $client = new {{call .Fnc.camelize .Pkg.Name}}\Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}'1a2b3', $clientOptions);
75 | ```
76 |
77 | ##### Oauth client secret
78 |
79 | ```php
80 | $auth = array('client_id' => '09a8b7', 'client_secret' => '1a2b3');
81 |
82 | $client = new {{call .Fnc.camelize .Pkg.Name}}\Client({{if .Api.BaseAsArg}}'{{.Api.Base}}', {{end}}$auth, $clientOptions);
83 | ```
84 | {{end}}
85 | ### Client Options
86 |
87 | The following options are available while instantiating a client:
88 |
89 | * __base__: Base url for the api
90 | * __api_version__: Default version of the api (to be used in url)
91 | * __user_agent__: Default user-agent for all requests
92 | * __headers__: Default headers for all requests
93 | * __request_type__: Default format of the request body{{if .Api.Response.Suffix}}
94 | * __response_type__: Default format of the response (to be used in url suffix){{end}}
95 |
96 | ### Response information
97 |
98 | __All the callbacks provided to an api call will receive the response as shown below__
99 |
100 | ```php
101 | $response = $client->klass('args')->method('args', $methodOptions);
102 |
103 | $response->code;
104 | // >>> 200
105 |
106 | $response->headers;
107 | // >>> array('x-server' => 'apache')
108 | ```
109 | {{if .Api.Response.Formats.Html}}
110 | ##### HTML/TEXT response
111 |
112 | When the response sent by server is either __html__ or __text__, it is not changed in any way
113 |
114 | ```php
115 | $response->body;
116 | // >>> 'The username is pksunkara!'
117 | ```
118 | {{end}}{{if .Api.Response.Formats.Json}}
119 | ##### JSON response
120 |
121 | When the response sent by server is __json__, it is decoded into an array
122 |
123 | ```php
124 | $response->body;
125 | // >>> array('user' => 'pksunkara')
126 | ```
127 | {{end}}
128 | ### Method Options
129 |
130 | The following options are available while calling a method of an api:
131 |
132 | * __api_version__: Version of the api (to be used in url)
133 | * __headers__: Headers for the request
134 | * __query__: Query parameters for the url
135 | * __body__: Body of the request
136 | * __request_type__: Format of the request body{{if .Api.Response.Suffix}}
137 | * __response_type__: Format of the response (to be used in url suffix){{end}}
138 |
139 | ### Request body information
140 |
141 | Set __request_type__ in options to modify the body accordingly
142 |
143 | ##### RAW request
144 |
145 | When the value is set to __raw__, don't modify the body at all.
146 |
147 | ```php
148 | $body = 'username=pksunkara';
149 | // >>> 'username=pksunkara'
150 | ```
151 | {{if .Api.Request.Formats.Form}}
152 | ##### FORM request
153 |
154 | When the value is set to __form__, urlencode the body.
155 |
156 | ```php
157 | $body = array('user' => 'pksunkara');
158 | // >>> 'user=pksunkara'
159 | ```
160 | {{end}}{{if .Api.Request.Formats.Json}}
161 | ##### JSON request
162 |
163 | When the value is set to __json__, JSON encode the body.
164 |
165 | ```php
166 | $body = array('user' => 'pksunkara');
167 | // >>> '{"user": "pksunkara"}'
168 | ```
169 | {{end}}{{with $data := .}}{{range .Api.Classes}}
170 | ### {{(index $data.Doc .Name).Title}} api
171 |
172 | {{(index $data.Doc .Name).Desc}}{{with .Args}}
173 |
174 | The following arguments are required:
175 | {{end}}{{with $class := .}}{{range .Args}}
176 | * __{{.}}__: {{(index ((index $data.Doc $class.Name).Args) .).Desc}}{{end}}
177 |
178 | ```php
179 | ${{call $data.Fnc.camelizeDownFirst $class.Name}} = $client->{{call $data.Fnc.camelizeDownFirst $class.Name}}({{call $data.Fnc.prnt.php .Args ((index $data.Doc $class.Name).Args) ", " false}});
180 | ```
181 | {{range $class.Functions}}
182 | ##### {{(index ((index $data.Doc $class.Name).Functions) .Name).Title}} ({{call $data.Fnc.upper (or .Method "get")}} {{.Path}})
183 |
184 | {{(index ((index $data.Doc $class.Name).Functions) .Name).Desc}}{{with .Params}}
185 |
186 | The following arguments are required:
187 | {{end}}{{with $method := .}}{{range .Params}}{{if .Required}}
188 | * __{{.Name}}__: {{(index ((index ((index $data.Doc $class.Name).Functions) $method.Name).Params) .Name).Desc}}{{end}}{{end}}{{end}}
189 |
190 | ```php
191 | $response = ${{call $data.Fnc.camelizeDownFirst $class.Name}}->{{call $data.Fnc.camelizeDownFirst .Name}}({{call $data.Fnc.prnt.php .Params ((index ((index $data.Doc $class.Name).Functions) .Name).Params) ", " true}}$options);
192 | ```
193 | {{end}}{{end}}{{end}}{{end}}
194 | ## Contributors
195 | Here is a list of [Contributors](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-php/contributors)
196 |
197 | ### TODO
198 |
199 | ## License
200 | {{.Pkg.License}}
201 |
202 | ## Bug Reports
203 | Report [here](https://{{.Pkg.Git.Site}}/{{.Pkg.Git.User}}/{{.Pkg.Git.Name}}-php/issues).
204 |
205 | ## Contact
206 | {{.Pkg.Author.Name}} ({{.Pkg.Author.Email}})
207 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # alpaca [](https://travis-ci.org/pksunkara/alpaca) [](https://gitter.im/pksunkara/alpaca)
2 |
3 | Api Libraries Powered And Created by Alpaca
4 |
5 | ---
6 |
7 | Tired of maintaining API libraries in different languages for your website API? _This is for you_
8 |
9 | You have an API for your website but no API libraries for whatever reason? _This is for you_
10 |
11 | You are planning to build an API for your website and develop API libraries? _This is for you_
12 |
13 | ---
14 |
15 | You define your API according to the format given below, __alpaca__ builds the API libraries along with their documentation. All you have to do is publishing them to their respective package managers.
16 |
17 | Join us at [gitter](https://gitter.im/pksunkara/alpaca) if you need any help.
18 |
19 | ## Installation
20 |
21 | You can download the binaries (v0.2.1)
22 |
23 | * Architecture i386 [ [linux](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_linux_386.tar.gz?direct) / [windows](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_windows_386.zip?direct) / [darwin](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_darwin_386.zip?direct) / [freebsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_freebsd_386.zip?direct) / [openbsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_openbsd_386.zip?direct) / [netbsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_netbsd_386.zip?direct) / [plan9](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_plan9_386.zip?direct) ]
24 | * Architecture amd64 [ [linux](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_linux_amd64.tar.gz?direct) / [windows](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_windows_amd64.zip?direct) / [darwin](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_darwin_amd64.zip?direct) / [freebsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_freebsd_amd64.zip?direct) / [openbsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_openbsd_amd64.zip?direct) / [netbsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_netbsd_amd64.zip?direct) ]
25 | * Architecture arm [ [linux](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_linux_arm.tar.gz?direct) / [freebsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_freebsd_arm.zip?direct) / [netbsd](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_netbsd_arm.zip?direct) ]
26 |
27 | Or by using deb packages (v0.2.1)
28 |
29 | * [ [i386](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_i386.deb?direct) / [amd64](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_amd64.deb?direct) / [armhf](https://dl.bintray.com//content/pksunkara/utils/alpaca_0.2.1_armhf.deb?direct) ]
30 |
31 | Or by using golang (v1.2)
32 |
33 | ```bash
34 | # Clone the project into your golang workspace
35 | $ git clone git://github.com/pksunkara/alpaca
36 | $ cd alpaca
37 |
38 | # Install program
39 | $ make && make install
40 | ```
41 |
42 | ## Examples
43 |
44 | You can find some api definitions in the [examples](https://github.com/pksunkara/alpaca/tree/master/examples) directory. The api libraries generated are at [https://github.com/alpaca-api](https://github.com/alpaca-api)
45 |
46 | Completed api definitions are [buffer](https://github.com/pksunkara/alpaca/tree/master/examples/buffer).
47 |
48 | ## Usage
49 |
50 | ```bash
51 | $ alpaca
52 | ```
53 |
54 | The path here should be a directory with `api.json`, `pkg.json`, `doc.json`
55 |
56 | ```
57 | Usage:
58 | alpaca [options]
59 |
60 | Application Options:
61 | -v, --version Show version information
62 |
63 | Language Options:
64 | --no-php Do not write php library
65 | --no-python Do not write python library
66 | --no-ruby Do not write ruby library
67 | --no-node Do not write node library
68 |
69 | Help Options:
70 | -h, --help Show this help message
71 | ```
72 |
73 | _Please remove the comments when actually using these json files_
74 |
75 | #### pkg.json
76 |
77 | All the following fields are required unless mentioned.
78 |
79 | ```js
80 | {
81 | "name": "Example", // Name of the api (also used as class name for the library)
82 | "package": "example-alpaca", // Name of the package
83 | "version": "0.1.0", // Version of the package
84 | "url": "https://exampleapp.com", // URL of the api
85 | "keywords": ["alpaca", "exampleapp", "api"], // Keywords for the package
86 | "official": false, // Are the api libraries official?
87 | "author": {
88 | "name": "Pavan Kumar Sunkara", // Name of the package author
89 | "email": "pavan.sss1991@gmail.com", // Email of the package author
90 | "url": "http://github.com/pksunkara" // URL of the package author
91 | },
92 | "git": { // Used in the package definition
93 | "site": "github.com", // Name of the git website
94 | "user": "alpaca-api", // Username of the git website
95 | "name": "buffer" // Namespace of the git repositories
96 | },
97 | "license": "MIT", // License of the package
98 | "php": { // Required only if creating php api lib
99 | "vendor": "pksunkara" // Packagist vendor name for the package
100 | },
101 | "python": { // Required only if creating python api lib
102 | "license": "MIT License" // Classifier of the license used for the module
103 | }
104 | }
105 | ```
106 |
107 | #### api.json
108 |
109 | All the following fields are required unless mentioned.
110 |
111 | ```js
112 | {
113 | "base": "https://exampleapp.com", // Base URL of the api
114 | "base_as_arg": true, // Force Base URL to be an argument in generated clients [optional] (default: false)
115 | "version": "v1", // Default version for the api (https://api.example.com{/version}/users) [optional]
116 | "no_verify_ssl": true, // Do not verify SSL cert [optional] (default: false)
117 | "authorization": { // Authorization strategies
118 | "need_auth": true, // Authentication is compulsory [optional] (default: false)
119 | "basic" : true, // Basic authentication [optional] (default: false)
120 | "header": true, // Token in authorization header [optional] (default: false)
121 | "header_prefix": "oompaloompa", // The first word in header if using token auth header [optional] (default: token)
122 | "oauth" : true // OAUTH authorization [optional] (default: false)
123 | },
124 | "request": { // Settings for requests to the api
125 | "formats": { // Format of the request body
126 | "default": "form", // Default format for the request body [optional] (default: raw)
127 | "form": true, // Support form-url-encoded? [optional] (default: false)
128 | "json": true // Support json? [optional] (default: false)
129 | }
130 | },
131 | "response": { // Settings for responses from the api
132 | "suffix": true, // Should the urls be suffixed with response format? [optional] (default: false)
133 | "formats": { // Format of the response body
134 | "default": "json", // Default response format. Used when 'suffix' is 'true'
135 | "html": true, // Support html? [optional] (default: false)
136 | "json": true // Support json? [optional] (default: false)
137 | }
138 | },
139 | "error": { // Required if response format is 'json'
140 | "message": "error" // The field to be used from the response body for error message
141 | },
142 | "class": { // The classes for the api
143 | "users": { // Name of a class of the api
144 | "args": ["login"], // Arguments required for the api class [optional]
145 | "profile": { // Name of a method of the api
146 | "path": "/users/:login/:type", // URL of the api method
147 | "method": "post", // HTTP method of the api method [optional] (default: get)
148 | "params": [ // Parameters for the api method [optional]
149 | {
150 | "name": "type", // Name of the parameter
151 | "required": true, // The parameter will become an argument of api method [optional] (default: false)
152 | "url_use": true // This parameter is only used to build url [optional] (default: false)
153 | },
154 | {
155 | "name": "bio",
156 | "required": true
157 | }
158 | ]
159 | }
160 | }
161 | }
162 | }
163 | ```
164 |
165 | #### doc.json
166 |
167 | The following is filled according to the entries in `api.json`
168 |
169 | ```js
170 | {
171 | "users": { // Name of a class of the api
172 | "title": "Users", // Title of the api class
173 | "desc": "Returns user api instance", // Description of the api class
174 | "args": { // Arguments of the api class
175 | "login": { // Name of the argument
176 | "desc": "Username of the user", // Description of the argument
177 | "value": "pksunkara" // Value of the argument in docs
178 | }
179 | },
180 | "profile": { // Name of a method of the api
181 | "title": "Edit profile", // Title of the api method
182 | "desc": "Edit the user's profile", // Description of the api method
183 | "params": { // Parameter of the api class
184 | "bio": { // Name of the parameter
185 | "desc": "Short bio in profile", // Description of the parameter
186 | "value": "I am awesome!" // Value of the parameter in docs
187 | },
188 | "type": {
189 | "desc": "Circle of the profile",
190 | "value": "friends"
191 | }
192 | }
193 | }
194 | }
195 | }
196 | ```
197 |
198 | ### Request formats
199 |
200 | Supported request formats are `raw`, `form`, `json`. The format `raw` is always true.
201 |
202 | This means, the `body` set in the options when calling an API method will be able to be encoded according to the respective `request_type`
203 |
204 | __If set to `raw`, body is not modified at all__
205 |
206 | ### Response formats
207 |
208 | Supported response formats are `html`, `json`.
209 |
210 | ### Authorization strategies
211 |
212 | Supported are `basic`, `header`, `oauth`
213 |
214 | ### Language Versions
215 |
216 | Supported programming language versions are:
217 |
218 | | Language | V | E | R | S | I | O | N |
219 | |----------|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|:-----:|
220 | | node | 0.8 | 0.9 | 0.10 | 0.11 | 0.12 | | |
221 | | php | 5.4 | 5.5 | | | | | |
222 | | python | 2.6 | 2.7 | 3.2 | 3.3 | | | |
223 | | ruby | 1.8.7 | 1.9.1 | 1.9.2 | 1.9.3 | 2.0.0 | 2.1.0 | 2.1.1 |
224 |
225 | ### Package Managers
226 |
227 | | Language | Package Manager |
228 | |----------|----------------------------------------------------|
229 | | node | [https://npmjs.org](https://npmjs.org) |
230 | | php | [https://packagist.org](https://packagist.org) |
231 | | python | [https://pypi.python.org](https://pypi.python.org) |
232 | | ruby | [https://rubygems.org](https://rubygems.org) |
233 |
234 | ## Testing
235 |
236 | Check [here](https://github.com/pksunkara/alpaca/tree/testing) to learn about testing.
237 |
238 | ## Contributors
239 |
240 | Here is a list of [Contributors](https://github.com/pksunkara/alpaca/contributors)
241 |
242 | __I accept pull requests and guarantee a reply back within a day__
243 |
244 | ### TODO
245 |
246 | You get internet points for pull requesting the following features.
247 |
248 | ##### Responses
249 |
250 | * [Add support for XML](https://github.com/pksunkara/alpaca/issues/36)
251 | * [Add support for CSV](https://github.com/pksunkara/alpaca/issues/36)
252 |
253 | ##### Requests
254 |
255 | * HTTP Method Overloading
256 | * What about file uploads?
257 |
258 | ##### API
259 |
260 | * Check returned status code
261 | * Special case for 204:true and 404:false
262 |
263 | ##### Libraries
264 |
265 | * Pagination support
266 | * Classes inside classes (so on..)
267 | * Validations for params/body in api methods
268 | * Allow customization of errors
269 | * Tests for libraries (lots and lots of tests)
270 |
271 | ##### Readme
272 |
273 | * [Optional params available](https://github.com/pksunkara/alpaca/issues/57)
274 | * Return types of api calls
275 |
276 | ##### Comments
277 |
278 | * The descriptions should be wrapped
279 | * Align @param descriptions
280 |
281 | ##### Formats
282 |
283 | * [Support YAML](https://github.com/pksunkara/alpaca/issues/63)
284 | * [Support API blueprint](https://github.com/pksunkara/alpaca/issues/56)
285 | * [Support Swagger](https://github.com/pksunkara/alpaca/issues/61)
286 | * [Support WADL](https://github.com/pksunkara/alpaca/issues/13)
287 | * [Support JSON Schema](https://github.com/pksunkara/alpaca/issues/17)
288 | * [Support RAML](https://github.com/pksunkara/alpaca/issues/54)
289 |
290 | ##### Languages
291 |
292 | * [Support Java](https://github.com/pksunkara/alpaca/issues/11)
293 | * [Support Go](https://github.com/pksunkara/alpaca/issues/9)
294 | * [Support Clojure](https://github.com/pksunkara/alpaca/issues/49)
295 | * [Support Rust](https://github.com/pksunkara/alpaca/issues/62)
296 | * [Support Swift](https://github.com/pksunkara/alpaca/issues/64)
297 | * Support C, C++, Perl, Scala, C#, Erlang, Lua, Haskell, D, Julia, Groovy
298 | * Build cli tool for APIs (bash? python? go?)
299 |
300 | ### Support Projects
301 |
302 | Alternatively, you can write your own converter from `alpaca.json` to the following
303 |
304 | * Convert into API Blueprint
305 | * Convert into Swagger
306 |
307 | ## License
308 |
309 | MIT/X11
310 |
311 | ## Bug Reports
312 |
313 | Report [here](http://github.com/pksunkara/alpaca/issues). __Guaranteed reply within a day__.
314 |
315 | ## Contact
316 |
317 | Pavan Kumar Sunkara (pavan.sss1991@gmail.com)
318 |
319 | Follow me on [github](https://github.com/users/follow?target=pksunkara), [twitter](http://twitter.com/pksunkara)
320 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Mozilla Public License, version 2.0
2 |
3 | 1. Definitions
4 |
5 | 1.1. "Contributor"
6 |
7 | means each individual or legal entity that creates, contributes to the
8 | creation of, or owns Covered Software.
9 |
10 | 1.2. "Contributor Version"
11 |
12 | means the combination of the Contributions of others (if any) used by a
13 | Contributor and that particular Contributor's Contribution.
14 |
15 | 1.3. "Contribution"
16 |
17 | means Covered Software of a particular Contributor.
18 |
19 | 1.4. "Covered Software"
20 |
21 | means Source Code Form to which the initial Contributor has attached the
22 | notice in Exhibit A, the Executable Form of such Source Code Form, and
23 | Modifications of such Source Code Form, in each case including portions
24 | thereof.
25 |
26 | 1.5. "Incompatible With Secondary Licenses"
27 | means
28 |
29 | a. that the initial Contributor has attached the notice described in
30 | Exhibit B to the Covered Software; or
31 |
32 | b. that the Covered Software was made available under the terms of
33 | version 1.1 or earlier of the License, but not also under the terms of
34 | a Secondary License.
35 |
36 | 1.6. "Executable Form"
37 |
38 | means any form of the work other than Source Code Form.
39 |
40 | 1.7. "Larger Work"
41 |
42 | means a work that combines Covered Software with other material, in a
43 | separate file or files, that is not Covered Software.
44 |
45 | 1.8. "License"
46 |
47 | means this document.
48 |
49 | 1.9. "Licensable"
50 |
51 | means having the right to grant, to the maximum extent possible, whether
52 | at the time of the initial grant or subsequently, any and all of the
53 | rights conveyed by this License.
54 |
55 | 1.10. "Modifications"
56 |
57 | means any of the following:
58 |
59 | a. any file in Source Code Form that results from an addition to,
60 | deletion from, or modification of the contents of Covered Software; or
61 |
62 | b. any new file in Source Code Form that contains any Covered Software.
63 |
64 | 1.11. "Patent Claims" of a Contributor
65 |
66 | means any patent claim(s), including without limitation, method,
67 | process, and apparatus claims, in any patent Licensable by such
68 | Contributor that would be infringed, but for the grant of the License,
69 | by the making, using, selling, offering for sale, having made, import,
70 | or transfer of either its Contributions or its Contributor Version.
71 |
72 | 1.12. "Secondary License"
73 |
74 | means either the GNU General Public License, Version 2.0, the GNU Lesser
75 | General Public License, Version 2.1, the GNU Affero General Public
76 | License, Version 3.0, or any later versions of those licenses.
77 |
78 | 1.13. "Source Code Form"
79 |
80 | means the form of the work preferred for making modifications.
81 |
82 | 1.14. "You" (or "Your")
83 |
84 | means an individual or a legal entity exercising rights under this
85 | License. For legal entities, "You" includes any entity that controls, is
86 | controlled by, or is under common control with You. For purposes of this
87 | definition, "control" means (a) the power, direct or indirect, to cause
88 | the direction or management of such entity, whether by contract or
89 | otherwise, or (b) ownership of more than fifty percent (50%) of the
90 | outstanding shares or beneficial ownership of such entity.
91 |
92 |
93 | 2. License Grants and Conditions
94 |
95 | 2.1. Grants
96 |
97 | Each Contributor hereby grants You a world-wide, royalty-free,
98 | non-exclusive license:
99 |
100 | a. under intellectual property rights (other than patent or trademark)
101 | Licensable by such Contributor to use, reproduce, make available,
102 | modify, display, perform, distribute, and otherwise exploit its
103 | Contributions, either on an unmodified basis, with Modifications, or
104 | as part of a Larger Work; and
105 |
106 | b. under Patent Claims of such Contributor to make, use, sell, offer for
107 | sale, have made, import, and otherwise transfer either its
108 | Contributions or its Contributor Version.
109 |
110 | 2.2. Effective Date
111 |
112 | The licenses granted in Section 2.1 with respect to any Contribution
113 | become effective for each Contribution on the date the Contributor first
114 | distributes such Contribution.
115 |
116 | 2.3. Limitations on Grant Scope
117 |
118 | The licenses granted in this Section 2 are the only rights granted under
119 | this License. No additional rights or licenses will be implied from the
120 | distribution or licensing of Covered Software under this License.
121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a
122 | Contributor:
123 |
124 | a. for any code that a Contributor has removed from Covered Software; or
125 |
126 | b. for infringements caused by: (i) Your and any other third party's
127 | modifications of Covered Software, or (ii) the combination of its
128 | Contributions with other software (except as part of its Contributor
129 | Version); or
130 |
131 | c. under Patent Claims infringed by Covered Software in the absence of
132 | its Contributions.
133 |
134 | This License does not grant any rights in the trademarks, service marks,
135 | or logos of any Contributor (except as may be necessary to comply with
136 | the notice requirements in Section 3.4).
137 |
138 | 2.4. Subsequent Licenses
139 |
140 | No Contributor makes additional grants as a result of Your choice to
141 | distribute the Covered Software under a subsequent version of this
142 | License (see Section 10.2) or under the terms of a Secondary License (if
143 | permitted under the terms of Section 3.3).
144 |
145 | 2.5. Representation
146 |
147 | Each Contributor represents that the Contributor believes its
148 | Contributions are its original creation(s) or it has sufficient rights to
149 | grant the rights to its Contributions conveyed by this License.
150 |
151 | 2.6. Fair Use
152 |
153 | This License is not intended to limit any rights You have under
154 | applicable copyright doctrines of fair use, fair dealing, or other
155 | equivalents.
156 |
157 | 2.7. Conditions
158 |
159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
160 | Section 2.1.
161 |
162 |
163 | 3. Responsibilities
164 |
165 | 3.1. Distribution of Source Form
166 |
167 | All distribution of Covered Software in Source Code Form, including any
168 | Modifications that You create or to which You contribute, must be under
169 | the terms of this License. You must inform recipients that the Source
170 | Code Form of the Covered Software is governed by the terms of this
171 | License, and how they can obtain a copy of this License. You may not
172 | attempt to alter or restrict the recipients' rights in the Source Code
173 | Form.
174 |
175 | 3.2. Distribution of Executable Form
176 |
177 | If You distribute Covered Software in Executable Form then:
178 |
179 | a. such Covered Software must also be made available in Source Code Form,
180 | as described in Section 3.1, and You must inform recipients of the
181 | Executable Form how they can obtain a copy of such Source Code Form by
182 | reasonable means in a timely manner, at a charge no more than the cost
183 | of distribution to the recipient; and
184 |
185 | b. You may distribute such Executable Form under the terms of this
186 | License, or sublicense it under different terms, provided that the
187 | license for the Executable Form does not attempt to limit or alter the
188 | recipients' rights in the Source Code Form under this License.
189 |
190 | 3.3. Distribution of a Larger Work
191 |
192 | You may create and distribute a Larger Work under terms of Your choice,
193 | provided that You also comply with the requirements of this License for
194 | the Covered Software. If the Larger Work is a combination of Covered
195 | Software with a work governed by one or more Secondary Licenses, and the
196 | Covered Software is not Incompatible With Secondary Licenses, this
197 | License permits You to additionally distribute such Covered Software
198 | under the terms of such Secondary License(s), so that the recipient of
199 | the Larger Work may, at their option, further distribute the Covered
200 | Software under the terms of either this License or such Secondary
201 | License(s).
202 |
203 | 3.4. Notices
204 |
205 | You may not remove or alter the substance of any license notices
206 | (including copyright notices, patent notices, disclaimers of warranty, or
207 | limitations of liability) contained within the Source Code Form of the
208 | Covered Software, except that You may alter any license notices to the
209 | extent required to remedy known factual inaccuracies.
210 |
211 | 3.5. Application of Additional Terms
212 |
213 | You may choose to offer, and to charge a fee for, warranty, support,
214 | indemnity or liability obligations to one or more recipients of Covered
215 | Software. However, You may do so only on Your own behalf, and not on
216 | behalf of any Contributor. You must make it absolutely clear that any
217 | such warranty, support, indemnity, or liability obligation is offered by
218 | You alone, and You hereby agree to indemnify every Contributor for any
219 | liability incurred by such Contributor as a result of warranty, support,
220 | indemnity or liability terms You offer. You may include additional
221 | disclaimers of warranty and limitations of liability specific to any
222 | jurisdiction.
223 |
224 | 4. Inability to Comply Due to Statute or Regulation
225 |
226 | If it is impossible for You to comply with any of the terms of this License
227 | with respect to some or all of the Covered Software due to statute,
228 | judicial order, or regulation then You must: (a) comply with the terms of
229 | this License to the maximum extent possible; and (b) describe the
230 | limitations and the code they affect. Such description must be placed in a
231 | text file included with all distributions of the Covered Software under
232 | this License. Except to the extent prohibited by statute or regulation,
233 | such description must be sufficiently detailed for a recipient of ordinary
234 | skill to be able to understand it.
235 |
236 | 5. Termination
237 |
238 | 5.1. The rights granted under this License will terminate automatically if You
239 | fail to comply with any of its terms. However, if You become compliant,
240 | then the rights granted under this License from a particular Contributor
241 | are reinstated (a) provisionally, unless and until such Contributor
242 | explicitly and finally terminates Your grants, and (b) on an ongoing
243 | basis, if such Contributor fails to notify You of the non-compliance by
244 | some reasonable means prior to 60 days after You have come back into
245 | compliance. Moreover, Your grants from a particular Contributor are
246 | reinstated on an ongoing basis if such Contributor notifies You of the
247 | non-compliance by some reasonable means, this is the first time You have
248 | received notice of non-compliance with this License from such
249 | Contributor, and You become compliant prior to 30 days after Your receipt
250 | of the notice.
251 |
252 | 5.2. If You initiate litigation against any entity by asserting a patent
253 | infringement claim (excluding declaratory judgment actions,
254 | counter-claims, and cross-claims) alleging that a Contributor Version
255 | directly or indirectly infringes any patent, then the rights granted to
256 | You by any and all Contributors for the Covered Software under Section
257 | 2.1 of this License shall terminate.
258 |
259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
260 | license agreements (excluding distributors and resellers) which have been
261 | validly granted by You or Your distributors under this License prior to
262 | termination shall survive termination.
263 |
264 | 6. Disclaimer of Warranty
265 |
266 | Covered Software is provided under this License on an "as is" basis,
267 | without warranty of any kind, either expressed, implied, or statutory,
268 | including, without limitation, warranties that the Covered Software is free
269 | of defects, merchantable, fit for a particular purpose or non-infringing.
270 | The entire risk as to the quality and performance of the Covered Software
271 | is with You. Should any Covered Software prove defective in any respect,
272 | You (not any Contributor) assume the cost of any necessary servicing,
273 | repair, or correction. This disclaimer of warranty constitutes an essential
274 | part of this License. No use of any Covered Software is authorized under
275 | this License except under this disclaimer.
276 |
277 | 7. Limitation of Liability
278 |
279 | Under no circumstances and under no legal theory, whether tort (including
280 | negligence), contract, or otherwise, shall any Contributor, or anyone who
281 | distributes Covered Software as permitted above, be liable to You for any
282 | direct, indirect, special, incidental, or consequential damages of any
283 | character including, without limitation, damages for lost profits, loss of
284 | goodwill, work stoppage, computer failure or malfunction, or any and all
285 | other commercial damages or losses, even if such party shall have been
286 | informed of the possibility of such damages. This limitation of liability
287 | shall not apply to liability for death or personal injury resulting from
288 | such party's negligence to the extent applicable law prohibits such
289 | limitation. Some jurisdictions do not allow the exclusion or limitation of
290 | incidental or consequential damages, so this exclusion and limitation may
291 | not apply to You.
292 |
293 | 8. Litigation
294 |
295 | Any litigation relating to this License may be brought only in the courts
296 | of a jurisdiction where the defendant maintains its principal place of
297 | business and such litigation shall be governed by laws of that
298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing
299 | in this Section shall prevent a party's ability to bring cross-claims or
300 | counter-claims.
301 |
302 | 9. Miscellaneous
303 |
304 | This License represents the complete agreement concerning the subject
305 | matter hereof. If any provision of this License is held to be
306 | unenforceable, such provision shall be reformed only to the extent
307 | necessary to make it enforceable. Any law or regulation which provides that
308 | the language of a contract shall be construed against the drafter shall not
309 | be used to construe this License against a Contributor.
310 |
311 |
312 | 10. Versions of the License
313 |
314 | 10.1. New Versions
315 |
316 | Mozilla Foundation is the license steward. Except as provided in Section
317 | 10.3, no one other than the license steward has the right to modify or
318 | publish new versions of this License. Each version will be given a
319 | distinguishing version number.
320 |
321 | 10.2. Effect of New Versions
322 |
323 | You may distribute the Covered Software under the terms of the version
324 | of the License under which You originally received the Covered Software,
325 | or under the terms of any subsequent version published by the license
326 | steward.
327 |
328 | 10.3. Modified Versions
329 |
330 | If you create software not governed by this License, and you want to
331 | create a new license for such software, you may create and use a
332 | modified version of this License if you rename the license and remove
333 | any references to the name of the license steward (except to note that
334 | such modified license differs from this License).
335 |
336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary
337 | Licenses If You choose to distribute Source Code Form that is
338 | Incompatible With Secondary Licenses under the terms of this version of
339 | the License, the notice described in Exhibit B of this License must be
340 | attached.
341 |
342 | Exhibit A - Source Code Form License Notice
343 |
344 | This Source Code Form is subject to the
345 | terms of the Mozilla Public License, v.
346 | 2.0. If a copy of the MPL was not
347 | distributed with this file, You can
348 | obtain one at
349 | http://mozilla.org/MPL/2.0/.
350 |
351 | If it is not possible or desirable to put the notice in a particular file,
352 | then You may include the notice in a location (such as a LICENSE file in a
353 | relevant directory) where a recipient would be likely to look for such a
354 | notice.
355 |
356 | You may add additional accurate notices of copyright ownership.
357 |
358 | Exhibit B - "Incompatible With Secondary Licenses" Notice
359 |
360 | This Source Code Form is "Incompatible
361 | With Secondary Licenses", as defined by
362 | the Mozilla Public License, v. 2.0.
363 |
--------------------------------------------------------------------------------