ruby_http_client 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.env_sample +4 -0
- data/.github/ISSUE_TEMPLATE +17 -0
- data/.gitignore +37 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +194 -0
- data/LICENSE +21 -0
- data/README.md +133 -0
- data/Rakefile +8 -0
- data/examples/example.rb +73 -0
- data/lib/config.rb +10 -0
- data/lib/ruby_http_client.rb +221 -0
- data/ruby_http_client.gemspec +22 -0
- data/test/test_ruby_http_client.rb +117 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 962d8241ec81889b1f89348c24fd6cc490a9aa98
|
4
|
+
data.tar.gz: 4cceab98eddf6359e7e8173e511b1018b803f882
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9c75159dfae79c5f06a7b1590aaa0d985e389099c87e258c381371993d524e2114eaabe9f7055eda1caa12c5a7cbace192fd22960cdbb93b168b96ffb7d02681
|
7
|
+
data.tar.gz: b13713f036cdd34a1054b6aa0cb046261c4787a9252575d0cbf335003d002477c77e49391458c75fec8b795d31ba931c1d4e2b2c3da9a133f2c79f57a8019d3a
|
data/.env_sample
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#### Issue Summary
|
2
|
+
|
3
|
+
A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, code examples.
|
4
|
+
|
5
|
+
|
6
|
+
#### Steps to Reproduce
|
7
|
+
|
8
|
+
1. This is the first step
|
9
|
+
2. This is the second step
|
10
|
+
3. Further steps, etc.
|
11
|
+
|
12
|
+
Any other information you want to share that is relevant to the issue being reported. Especially, why do you consider this to be a bug? What do you expect to happen instead?
|
13
|
+
|
14
|
+
#### Technical details:
|
15
|
+
|
16
|
+
* ruby-http-client Version: master (latest commit: [commit number])
|
17
|
+
* Ruby Version: 2.2
|
data/.gitignore
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
/.config
|
4
|
+
/coverage/
|
5
|
+
/InstalledFiles
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/spec/examples.txt
|
9
|
+
/test/tmp/
|
10
|
+
/test/version_tmp/
|
11
|
+
/tmp/
|
12
|
+
|
13
|
+
## Specific to RubyMotion:
|
14
|
+
.dat*
|
15
|
+
.repl_history
|
16
|
+
build/
|
17
|
+
|
18
|
+
## Documentation cache and generated files:
|
19
|
+
/.yardoc/
|
20
|
+
/_yardoc/
|
21
|
+
/doc/
|
22
|
+
/rdoc/
|
23
|
+
|
24
|
+
## Environment normalization:
|
25
|
+
/.bundle/
|
26
|
+
/vendor/bundle
|
27
|
+
/lib/bundler/man/
|
28
|
+
|
29
|
+
# for a library or gem, you might want to ignore these files since the code is
|
30
|
+
# intended to run in multiple environments; otherwise, check them in:
|
31
|
+
# Gemfile.lock
|
32
|
+
# .ruby-version
|
33
|
+
# .ruby-gemset
|
34
|
+
|
35
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
36
|
+
.rvmrc
|
37
|
+
.env
|
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.2
|
4
|
+
notifications:
|
5
|
+
hipchat:
|
6
|
+
rooms:
|
7
|
+
secure: gYBEwOGBTxHE2nrxsHQqp2UdjRtCX04wVLYEimeT9RG/0LClS4nzJF7DaXLWlAwgLPmk+KV2+nXuLO5oausBr9ODmWhho8G0F90RPR47NupcvT1RM+I2ZbxSjHCUICL22mdnZd8ye/mrk/YtFWYmgmH7ILRK3BuYovXFoKoRnLg=
|
8
|
+
template:
|
9
|
+
- '<a href="https://travis-ci.org/%{repository}/builds/%{build_id}">%{repository}
|
10
|
+
Build %{build_number}</a> on branch <i>%{branch}</i> by %{author}: <strong>%{message}</strong>
|
11
|
+
<a href="https://github.com/sendgrid/%{repository}/commits/%{commit}">View on GitHub</a>'
|
12
|
+
format: html
|
13
|
+
notify: false
|
14
|
+
script:
|
15
|
+
- rake
|
data/CHANGELOG.md
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
Hello! Thank you for choosing to help contribute to the ruby-http-client. There are many ways you can contribute and help is always welcome.
|
2
|
+
|
3
|
+
We use [Milestones](https://github.com/sendgrid/ruby-http-client/milestones) to help define current roadmaps, please feel free to grab an issue from the current milestone. Please indicate that you have begun work on it to avoid collisions. Once a PR is made, community review, comments, suggestions and additional PRs are welcomed and encouraged.
|
4
|
+
|
5
|
+
* [Feature Request](#feature_request)
|
6
|
+
* [Submit a Bug Report](#submit_a_bug_report)
|
7
|
+
* [Improvements to the Codebase](#improvements_to_the_codebase)
|
8
|
+
* [Understanding the Code Base](#understanding_the_codebase)
|
9
|
+
* [Testing](#testing)
|
10
|
+
* [Style Guidelines & Naming Conventions](#style_guidelines_and_naming_conventions)
|
11
|
+
* [Creating a Pull Request](#creating_a_pull_request)
|
12
|
+
|
13
|
+
There are a few ways to contribute, which we'll enumerate below:
|
14
|
+
|
15
|
+
<a name="feature_request"></a>
|
16
|
+
## Feature Request
|
17
|
+
|
18
|
+
If you'd like to make a feature request, please read this section.
|
19
|
+
|
20
|
+
The GitHub issue tracker is the preferred channel for library feature requests, but please respect the following restrictions:
|
21
|
+
|
22
|
+
- Please **search for existing issues** in order to ensure we don't have duplicate bugs/feature requests.
|
23
|
+
- Please be respectful and considerate of others when commenting on issues
|
24
|
+
|
25
|
+
<a name="submit_a_bug_report"></a>
|
26
|
+
## Submit a Bug Report
|
27
|
+
|
28
|
+
Note: DO NOT include your credentials in ANY code examples, descriptions, or media you make public.
|
29
|
+
|
30
|
+
A software bug is a demonstrable issue in the code base. In order for us to diagnose the issue and respond as quickly as possible, please add as much detail as possible into your bug report.
|
31
|
+
|
32
|
+
Before you decide to create a new issue, please try the following:
|
33
|
+
|
34
|
+
1. Check the Github issues tab if the identified issue has already been reported, if so, please add a +1 to the existing post.
|
35
|
+
2. Update to the latest version of this code and check if issue has already been fixed
|
36
|
+
3. Copy and fill in the Bug Report Template we have provided below
|
37
|
+
|
38
|
+
### Please use our Bug Report Template
|
39
|
+
|
40
|
+
In order to make the process easier, we've included a sample bug report template (borrowed from [Ghost](https://github.com/TryGhost/Ghost/)). The template uses [GitHub flavored markdown](https://help.github.com/articles/github-flavored-markdown/) for formatting.
|
41
|
+
|
42
|
+
```
|
43
|
+
Short and descriptive example bug report title
|
44
|
+
|
45
|
+
#### Issue Summary
|
46
|
+
|
47
|
+
A summary of the issue and the environment in which it occurs. If suitable, include the steps required to reproduce the bug. Please feel free to include screenshots, screencasts, code examples.
|
48
|
+
|
49
|
+
|
50
|
+
#### Steps to Reproduce
|
51
|
+
|
52
|
+
1. This is the first step
|
53
|
+
2. This is the second step
|
54
|
+
3. Further steps, etc.
|
55
|
+
|
56
|
+
Any other information you want to share that is relevant to the issue being reported. Especially, why do you consider this to be a bug? What do you expect to happen instead?
|
57
|
+
|
58
|
+
#### Technical details:
|
59
|
+
|
60
|
+
* ruby-http-client Version: master (latest commit: 2cb34372ef0f31352f7c90015a45e1200cb849da)
|
61
|
+
* Ruby Version: 2.2
|
62
|
+
```
|
63
|
+
|
64
|
+
<a name="improvements_to_the_codebase"></a>
|
65
|
+
## Improvements to the Codebase
|
66
|
+
|
67
|
+
We welcome direct contributions to the python-http-client code base. Thank you!
|
68
|
+
|
69
|
+
### Development Environment ###
|
70
|
+
|
71
|
+
#### Install and run locally ####
|
72
|
+
|
73
|
+
##### Prerequisites #####
|
74
|
+
|
75
|
+
* Ruby 2.2
|
76
|
+
* There are no external dependencies
|
77
|
+
|
78
|
+
##### Initial setup: #####
|
79
|
+
|
80
|
+
```
|
81
|
+
git clone https://github.com/sendgrid/ruby-http-client.git
|
82
|
+
cd ruby-http-client
|
83
|
+
cp .env_sample .env
|
84
|
+
```
|
85
|
+
|
86
|
+
Update your settings in `.env`
|
87
|
+
|
88
|
+
##### Execute: #####
|
89
|
+
|
90
|
+
See the [examples folder](https://github.com/sendgrid/ruby-http-client/tree/master/examples) to get started quickly.
|
91
|
+
|
92
|
+
<a name="understanding_the_codebase"></a>
|
93
|
+
## Understanding the Code Base
|
94
|
+
|
95
|
+
**/examples**
|
96
|
+
|
97
|
+
Working examples that demonstrate usage.
|
98
|
+
|
99
|
+
**ruby_http_client.rb**
|
100
|
+
|
101
|
+
An HTTP client with a fluent interface using method chaining and reflection. By returning self on [method_missing](https://github.com/sendgrid/ruby-http-client/blob/master/lib/ruby_http_client.rb#L209) and [_()](https://github.com/sendgrid/ruby-http-client/blob/master/lib/ruby_http_client.rb#L194), we can dynamically build the URL using method chaining and [method_missing](https://github.com/sendgrid/ruby-http-client/blob/master/lib/ruby_http_client.rb#L209) allows us to dynamically receive the method calls to achieve reflection.
|
102
|
+
|
103
|
+
This allows for the following mapping from a URL to a method chain:
|
104
|
+
|
105
|
+
`/api_client/{api_key_id}/version` maps to `client.api_client._(api_key_id).version.<method>()` where <method> is a [HTTP verb](https://github.com/sendgrid/ruby-http-client/blob/master/lib/ruby_http_client.rb#L38).
|
106
|
+
|
107
|
+
**congfig.rb**
|
108
|
+
|
109
|
+
Loads the environment variables.
|
110
|
+
|
111
|
+
<a name="testing"></a>
|
112
|
+
## Testing
|
113
|
+
|
114
|
+
All PRs require passing tests before the PR will be reviewed.
|
115
|
+
|
116
|
+
All test files are in the `[test](https://github.com/sendgrid/ruby-http-client/tree/master/test)` directory.
|
117
|
+
|
118
|
+
For the purposes of contributing to this repo, please update the [`test_ruby_http_client.rb`](https://github.com/sendgrid/ruby-http-client/blob/master/test/test_ruby_http_client.rb) file with unit tests as you modify the code.
|
119
|
+
|
120
|
+
To run the tests:
|
121
|
+
|
122
|
+
`rake`
|
123
|
+
|
124
|
+
All PRs require passing tests before the PR will be reviewed.
|
125
|
+
|
126
|
+
<a name="style_guidelines_and_naming_conventions"></a>
|
127
|
+
## Style Guidelines & Naming Conventions
|
128
|
+
|
129
|
+
Generally, we follow the style guidelines as suggested by the official language. However, we ask that you conform to the styles that already exist in the library. If you wish to deviate, please explain your reasoning.
|
130
|
+
|
131
|
+
* [Community Driven Style Guide](https://github.com/bbatsov/ruby-style-guide)
|
132
|
+
|
133
|
+
Please run your code through [rubocop](https://github.com/bbatsov/rubocop).
|
134
|
+
|
135
|
+
### Directory Structure
|
136
|
+
|
137
|
+
* `examples` for example calls
|
138
|
+
* `test`, for all tests
|
139
|
+
* `libs`, for the client library
|
140
|
+
|
141
|
+
## Creating a Pull Request<a name="creating_a_pull_request"></a>
|
142
|
+
|
143
|
+
1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork,
|
144
|
+
and configure the remotes:
|
145
|
+
|
146
|
+
```bash
|
147
|
+
# Clone your fork of the repo into the current directory
|
148
|
+
git clone https://github.com/sendgrid/ruby-http-client
|
149
|
+
# Navigate to the newly cloned directory
|
150
|
+
cd ruby-http-client
|
151
|
+
# Assign the original repo to a remote called "upstream"
|
152
|
+
git remote add upstream https://github.com/sendgrid/ruby-http-client
|
153
|
+
```
|
154
|
+
|
155
|
+
2. If you cloned a while ago, get the latest changes from upstream:
|
156
|
+
|
157
|
+
```bash
|
158
|
+
git checkout <dev-branch>
|
159
|
+
git pull upstream <dev-branch>
|
160
|
+
```
|
161
|
+
|
162
|
+
3. Create a new topic branch (off the main project development branch) to
|
163
|
+
contain your feature, change, or fix:
|
164
|
+
|
165
|
+
```bash
|
166
|
+
git checkout -b <topic-branch-name>
|
167
|
+
```
|
168
|
+
|
169
|
+
4. Commit your changes in logical chunks. Please adhere to these [git commit
|
170
|
+
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
|
171
|
+
or your code is unlikely be merged into the main project. Use Git's
|
172
|
+
[interactive rebase](https://help.github.com/articles/interactive-rebase)
|
173
|
+
feature to tidy up your commits before making them public.
|
174
|
+
|
175
|
+
4a. Create tests.
|
176
|
+
|
177
|
+
4b. Create or update the example code that demonstrates the functionality of this change to the code.
|
178
|
+
|
179
|
+
5. Locally merge (or rebase) the upstream development branch into your topic branch:
|
180
|
+
|
181
|
+
```bash
|
182
|
+
git pull [--rebase] upstream master
|
183
|
+
```
|
184
|
+
|
185
|
+
6. Push your topic branch up to your fork:
|
186
|
+
|
187
|
+
```bash
|
188
|
+
git push origin <topic-branch-name>
|
189
|
+
```
|
190
|
+
|
191
|
+
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
|
192
|
+
with a clear title and description against the `master` branch. All tests must be passing before we will review the PR.
|
193
|
+
|
194
|
+
If you have any additional questions, please feel free to [email](mailto:dx@sendgrid.com) us or create an issue in this repo.
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 SendGrid
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
[![Travis Badge](https://travis-ci.org/sendgrid/python-http-client.svg?branch=master)](https://travis-ci.org/sendgrid/ruby-http-client)
|
2
|
+
|
3
|
+
**Quickly and easily access any REST or REST-like API.**
|
4
|
+
|
5
|
+
Here is a quick example:
|
6
|
+
|
7
|
+
`GET /your/api/{param}/call`
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require ruby_http_client
|
11
|
+
global_headers = {'Authorization' => 'Basic XXXXXXX' }
|
12
|
+
client = SendGrid::Client(host: 'base_url', request_headers: global_headers)
|
13
|
+
client.your.api._(param).call.get
|
14
|
+
puts response.status_code
|
15
|
+
puts response.response_body
|
16
|
+
puts response.response_headers
|
17
|
+
```
|
18
|
+
|
19
|
+
`POST /your/api/{param}/call` with headers, query parameters and a request body with versioning.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
import ruby_http_client
|
23
|
+
global_headers = {'Authorization' => 'Basic XXXXXXX' }
|
24
|
+
client = SendGrid::Client(host: 'base_url', request_headers: global_headers)
|
25
|
+
query_params = { 'hello' => 0, 'world' => 1 }
|
26
|
+
request_headers = { 'X-Test' => 'test' }
|
27
|
+
data = { 'some' => 1, 'awesome' => 2, 'data' => 3}
|
28
|
+
response = client.your.api._(param).call.post(request_body: data,
|
29
|
+
query_params: query_params,
|
30
|
+
request_headers: request_headers)
|
31
|
+
puts response.status_code
|
32
|
+
puts response.response_body
|
33
|
+
puts response.response_headers
|
34
|
+
```
|
35
|
+
|
36
|
+
# Installation
|
37
|
+
|
38
|
+
`gem install ruby_http_client`
|
39
|
+
|
40
|
+
## Usage ##
|
41
|
+
|
42
|
+
Following is an example using SendGrid. You can get your free account [here](https://sendgrid.com/free?source=python-http-client).
|
43
|
+
|
44
|
+
First, update your .env with your [SENDGRID_API_KEY](https://app.sendgrid.com/settings/api_keys) and HOST. For this example HOST=https://api.sendgrid.com.
|
45
|
+
|
46
|
+
Following is an abridged example, here is the [full working code](https://github.com/sendgrid/ruby-http-client/tree/master/examples).
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
require ruby_http_client
|
50
|
+
|
51
|
+
Config.new
|
52
|
+
headers = JSON.parse('
|
53
|
+
{
|
54
|
+
"Authorization": "Bearer ' + ENV['SENDGRID_API_KEY'] + '",
|
55
|
+
"Content-Type": "application/json"
|
56
|
+
}
|
57
|
+
')
|
58
|
+
host = ENV['LOCAL_HOST']
|
59
|
+
client = SendGrid::Client.new(host: host, request_headers: headers)
|
60
|
+
|
61
|
+
# GET Collection
|
62
|
+
query_params = { 'limit' => 100, 'offset' => 0 }
|
63
|
+
response = client.version('v3').api_keys.get(query_params: query_params)
|
64
|
+
|
65
|
+
# POST
|
66
|
+
request_body = JSON.parse('
|
67
|
+
{
|
68
|
+
"name": "My API Key Ruby Test",
|
69
|
+
"scopes": [
|
70
|
+
"mail.send",
|
71
|
+
"alerts.create",
|
72
|
+
"alerts.read"
|
73
|
+
]
|
74
|
+
}
|
75
|
+
')
|
76
|
+
response = client.version('v3').api_keys.post(request_body: request_body)
|
77
|
+
api_key_id = JSON.parse(response.response_body)['api_key_id']
|
78
|
+
|
79
|
+
# GET Single
|
80
|
+
response = client.version('v3').api_keys._(api_key_id).get
|
81
|
+
|
82
|
+
# PATCH
|
83
|
+
request_body = JSON.parse('
|
84
|
+
{
|
85
|
+
"name": "A New Hope"
|
86
|
+
}
|
87
|
+
')
|
88
|
+
response = client.api_keys._(api_key_id).patch(request_body: request_body)
|
89
|
+
|
90
|
+
# PUT
|
91
|
+
request_body = JSON.parse('
|
92
|
+
{
|
93
|
+
"name": "A New Hope",
|
94
|
+
"scopes": [
|
95
|
+
"user.profile.read",
|
96
|
+
"user.profile.update"
|
97
|
+
]
|
98
|
+
}
|
99
|
+
')
|
100
|
+
response = client.api_keys._(api_key_id).put(request_body: request_body)
|
101
|
+
|
102
|
+
# DELETE
|
103
|
+
response = client.api_keys._(api_key_id).delete
|
104
|
+
```
|
105
|
+
|
106
|
+
# Announcements
|
107
|
+
|
108
|
+
[2016.03.17] - We hit version 1!
|
109
|
+
|
110
|
+
# Roadmap
|
111
|
+
|
112
|
+
[Milestones](https://github.com/sendgrid/ruby-http-client/milestones)
|
113
|
+
|
114
|
+
# How to Contribute
|
115
|
+
|
116
|
+
We encourage contribution to our libraries, please see our [CONTRIBUTING](https://github.com/sendgrid/ruby-http-client/blob/master/CONTRIBUTING.md) guide for details.
|
117
|
+
|
118
|
+
* [Feature Request](https://github.com/sendgrid/ruby-http-client/blob/master/CONTRIBUTING.md#feature_request)
|
119
|
+
* [Bug Reports](https://github.com/sendgrid/ruby-http-client/blob/master/CONTRIBUTING.md#submit_a_bug_report)
|
120
|
+
* [Improvements to the Codebase](https://github.com/sendgrid/ruby-http-client/blob/master/CONTRIBUTING.md#improvements_to_the_codebase)
|
121
|
+
|
122
|
+
# Thanks
|
123
|
+
|
124
|
+
We were inspired by the work done on [birdy](https://github.com/inueni/birdy) and [universalclient](https://github.com/dgreisen/universalclient).
|
125
|
+
|
126
|
+
# About
|
127
|
+
|
128
|
+
![SendGrid Logo]
|
129
|
+
(https://assets3.sendgrid.com/mkt/assets/logos_brands/small/sglogo_2015_blue-9c87423c2ff2ff393ebce1ab3bd018a4.png)
|
130
|
+
|
131
|
+
ruby-http-client is guided and supported by the SendGrid [Developer Experience Team](mailto:dx@sendgrid.com).
|
132
|
+
|
133
|
+
ruby-http-client is maintained and funded by SendGrid, Inc. The names and logos for ruby-http-client are trademarks of SendGrid, Inc.
|
data/Rakefile
ADDED
data/examples/example.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require_relative '../lib/config'
|
2
|
+
require_relative '../lib/ruby_http_client'
|
3
|
+
|
4
|
+
Config.new
|
5
|
+
headers = JSON.parse('
|
6
|
+
{
|
7
|
+
"Authorization": "Bearer ' + ENV['SENDGRID_API_KEY'] + '",
|
8
|
+
"Content-Type": "application/json"
|
9
|
+
}
|
10
|
+
')
|
11
|
+
host = ENV['LOCAL_HOST']
|
12
|
+
client = SendGrid::Client.new(host: host, request_headers: headers)
|
13
|
+
|
14
|
+
# GET Collection
|
15
|
+
query_params = { 'limit' => 100, 'offset' => 0 }
|
16
|
+
response = client.version('v3').api_keys.get(query_params: query_params)
|
17
|
+
puts response.status_code
|
18
|
+
puts response.response_body
|
19
|
+
puts response.response_headers
|
20
|
+
|
21
|
+
# POST
|
22
|
+
request_body = JSON.parse('
|
23
|
+
{
|
24
|
+
"name": "My API Key Ruby Test",
|
25
|
+
"scopes": [
|
26
|
+
"mail.send",
|
27
|
+
"alerts.create",
|
28
|
+
"alerts.read"
|
29
|
+
]
|
30
|
+
}
|
31
|
+
')
|
32
|
+
response = client.version('v3').api_keys.post(request_body: request_body)
|
33
|
+
puts response.status_code
|
34
|
+
puts response.response_body
|
35
|
+
puts response.response_headers
|
36
|
+
api_key_id = JSON.parse(response.response_body)['api_key_id']
|
37
|
+
|
38
|
+
# GET Single
|
39
|
+
response = client.version('v3').api_keys._(api_key_id).get
|
40
|
+
puts response.status_code
|
41
|
+
puts response.response_body
|
42
|
+
puts response.response_headers
|
43
|
+
|
44
|
+
# PATCH
|
45
|
+
request_body = JSON.parse('
|
46
|
+
{
|
47
|
+
"name": "A New Hope"
|
48
|
+
}
|
49
|
+
')
|
50
|
+
response = client.api_keys._(api_key_id).patch(request_body: request_body)
|
51
|
+
puts response.status_code
|
52
|
+
puts response.response_body
|
53
|
+
puts response.response_headers
|
54
|
+
|
55
|
+
# PUT
|
56
|
+
request_body = JSON.parse('
|
57
|
+
{
|
58
|
+
"name": "A New Hope",
|
59
|
+
"scopes": [
|
60
|
+
"user.profile.read",
|
61
|
+
"user.profile.update"
|
62
|
+
]
|
63
|
+
}
|
64
|
+
')
|
65
|
+
response = client.api_keys._(api_key_id).put(request_body: request_body)
|
66
|
+
puts response.status_code
|
67
|
+
puts response.response_body
|
68
|
+
puts response.response_headers
|
69
|
+
|
70
|
+
# DELETE
|
71
|
+
response = client.api_keys._(api_key_id).delete
|
72
|
+
puts response.status_code
|
73
|
+
puts response.response_headers
|
data/lib/config.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
# Quickly and easily access any REST or REST-like API.
|
2
|
+
module SendGrid
|
3
|
+
require 'json'
|
4
|
+
require 'net/http'
|
5
|
+
require 'net/https'
|
6
|
+
|
7
|
+
# Holds the response from an API call.
|
8
|
+
class Response
|
9
|
+
# * *Args* :
|
10
|
+
# - +response+ -> A NET::HTTP response object
|
11
|
+
#
|
12
|
+
attr_reader :status_code, :response_body, :response_headers
|
13
|
+
def initialize(response)
|
14
|
+
@status_code = response.code
|
15
|
+
@response_body = response.body
|
16
|
+
@response_headers = response.to_hash.inspect
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# A simple REST client.
|
21
|
+
class Client
|
22
|
+
attr_reader :host, :request_headers, :url_path
|
23
|
+
# * *Args* :
|
24
|
+
# - +host+ -> Base URL for the api. (e.g. https://api.sendgrid.com)
|
25
|
+
# - +request_headers+ -> A hash of the headers you want applied on
|
26
|
+
# all calls
|
27
|
+
# - +version+ -> The version number of the API.
|
28
|
+
# Subclass add_version for custom behavior.
|
29
|
+
# Or just pass the version as part of the URL
|
30
|
+
# (e.g. client._("/v3"))
|
31
|
+
# - +url_path+ -> A list of the url path segments
|
32
|
+
#
|
33
|
+
def initialize(host: nil, request_headers: nil, version: nil, url_path: nil)
|
34
|
+
@host = host
|
35
|
+
@request_headers = request_headers ? request_headers : {}
|
36
|
+
@version = version
|
37
|
+
@url_path = url_path ? url_path : []
|
38
|
+
@methods = %w(delete get patch post put)
|
39
|
+
@query_params = nil
|
40
|
+
@request_body = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Update the headers for the request
|
44
|
+
#
|
45
|
+
# * *Args* :
|
46
|
+
# - +request_headers+ -> Hash of request header key/values
|
47
|
+
#
|
48
|
+
def update_headers(request_headers)
|
49
|
+
@request_headers = @request_headers.merge(request_headers)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Build the final request headers
|
53
|
+
#
|
54
|
+
# * *Args* :
|
55
|
+
# - +request+ -> HTTP::NET request object
|
56
|
+
# * *Returns* :
|
57
|
+
# - HTTP::NET request object
|
58
|
+
#
|
59
|
+
def build_request_headers(request)
|
60
|
+
@request_headers.each do |key, value|
|
61
|
+
request[key] = value
|
62
|
+
end
|
63
|
+
request
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add the API version, subclass this function to customize
|
67
|
+
#
|
68
|
+
# * *Args* :
|
69
|
+
# - +url+ -> An empty url string
|
70
|
+
# * *Returns* :
|
71
|
+
# - The url string with the version pre-pended
|
72
|
+
#
|
73
|
+
def add_version(url)
|
74
|
+
url.concat("/#{@version}")
|
75
|
+
url
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add query parameters to the url
|
79
|
+
#
|
80
|
+
# * *Args* :
|
81
|
+
# - +url+ -> path to endpoint
|
82
|
+
# - +query_params+ -> hash of query parameters
|
83
|
+
# * *Returns* :
|
84
|
+
# - The url string with the query parameters appended
|
85
|
+
#
|
86
|
+
def build_query_params(url, query_params)
|
87
|
+
url.concat('?')
|
88
|
+
count = 0
|
89
|
+
query_params.each do |key, value|
|
90
|
+
url.concat('&') if count > 0
|
91
|
+
url.concat("#{key}=#{value}")
|
92
|
+
count += 1
|
93
|
+
end
|
94
|
+
url
|
95
|
+
end
|
96
|
+
|
97
|
+
# Set the query params, request headers and request body
|
98
|
+
#
|
99
|
+
# * *Args* :
|
100
|
+
# - +args+ -> array of args obtained from method_missing
|
101
|
+
#
|
102
|
+
def build_args(args)
|
103
|
+
args.each do |arg|
|
104
|
+
arg.each do |key, value|
|
105
|
+
case key.to_s
|
106
|
+
when 'query_params'
|
107
|
+
@query_params = value
|
108
|
+
when 'request_headers'
|
109
|
+
update_headers(value)
|
110
|
+
when 'request_body'
|
111
|
+
@request_body = value
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Build the final url
|
118
|
+
#
|
119
|
+
# * *Args* :
|
120
|
+
# - +query_params+ -> A hash of query parameters
|
121
|
+
# * *Returns* :
|
122
|
+
# - The final url string
|
123
|
+
#
|
124
|
+
def build_url(query_params: nil)
|
125
|
+
url = ''
|
126
|
+
url = add_version(url) if @version
|
127
|
+
@url_path.each do |x|
|
128
|
+
url.concat("/#{x}")
|
129
|
+
end
|
130
|
+
url = build_query_params(url, query_params) if query_params
|
131
|
+
URI.parse("#{@host}#{url}")
|
132
|
+
end
|
133
|
+
|
134
|
+
# Build the API request for HTTP::NET
|
135
|
+
#
|
136
|
+
# * *Args* :
|
137
|
+
# - +name+ -> method name, received from method_missing
|
138
|
+
# - +args+ -> args passed to the method
|
139
|
+
# * *Returns* :
|
140
|
+
# - A Response object from make_request
|
141
|
+
#
|
142
|
+
def build_request(name, args)
|
143
|
+
build_args(args) if args
|
144
|
+
uri = build_url(query_params: @query_params)
|
145
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
146
|
+
http = add_ssl(http)
|
147
|
+
net_http = Kernel.const_get('Net::HTTP::' + name.to_s.capitalize)
|
148
|
+
request = net_http.new(uri.request_uri)
|
149
|
+
request = build_request_headers(request)
|
150
|
+
request.body = @request_body.to_json if @request_body
|
151
|
+
make_request(http, request)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Make the API call and return the response. This is separated into
|
155
|
+
# it's own function, so we can mock it easily for testing.
|
156
|
+
#
|
157
|
+
# * *Args* :
|
158
|
+
# - +http+ -> NET:HTTP request object
|
159
|
+
# - +request+ -> NET::HTTP request object
|
160
|
+
# * *Returns* :
|
161
|
+
# - Response object
|
162
|
+
#
|
163
|
+
def make_request(http, request)
|
164
|
+
response = http.request(request)
|
165
|
+
Response.new(response)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Allow for https calls
|
169
|
+
#
|
170
|
+
# * *Args* :
|
171
|
+
# - +http+ -> HTTP::NET object
|
172
|
+
# * *Returns* :
|
173
|
+
# - HTTP::NET object
|
174
|
+
#
|
175
|
+
def add_ssl(http)
|
176
|
+
protocol = host.split(':')[0]
|
177
|
+
if protocol == 'https'
|
178
|
+
http.use_ssl = true
|
179
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
180
|
+
end
|
181
|
+
http
|
182
|
+
end
|
183
|
+
|
184
|
+
# Add variable values to the url.
|
185
|
+
# (e.g. /your/api/{variable_value}/call)
|
186
|
+
# Another example: if you have a ruby reserved word, such as true,
|
187
|
+
# in your url, you must use this method.
|
188
|
+
#
|
189
|
+
# * *Args* :
|
190
|
+
# - +name+ -> Name of the url segment
|
191
|
+
# * *Returns* :
|
192
|
+
# - Client object
|
193
|
+
#
|
194
|
+
def _(name = nil)
|
195
|
+
url_path = name ? @url_path.push(name) : @url_path
|
196
|
+
@url_path = []
|
197
|
+
Client.new(host: @host, request_headers: @request_headers,
|
198
|
+
version: @version, url_path: url_path)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Dynamically add segments to the url, then call a method.
|
202
|
+
# (e.g. client.name.name.get())
|
203
|
+
#
|
204
|
+
# * *Args* :
|
205
|
+
# - The args are autmoatically passed in
|
206
|
+
# * *Returns* :
|
207
|
+
# - Client object or Response object
|
208
|
+
#
|
209
|
+
def method_missing(name, *args, &_block)
|
210
|
+
# Capture the version
|
211
|
+
if name.to_s == 'version'
|
212
|
+
@version = args[0]
|
213
|
+
return _
|
214
|
+
end
|
215
|
+
# We have reached the end of the method chain, make the API call
|
216
|
+
return build_request(name, args) if @methods.include?(name.to_s)
|
217
|
+
# Add a segment to the URL
|
218
|
+
_(name)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'ruby_http_client'
|
7
|
+
spec.version = '1.0.0'
|
8
|
+
spec.authors = ['Elmer Thomas']
|
9
|
+
spec.email = 'dx@sendgrid.com'
|
10
|
+
spec.summary = 'A simple REST client'
|
11
|
+
spec.description = 'Quickly and easily access any REST or REST-like API.'
|
12
|
+
spec.homepage = 'http://github.com/sendgrid/ruby-http-client'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)/)
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'rake', '~> 0'
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
22
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require_relative '../lib/ruby_http_client'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
class MockResponse
|
5
|
+
attr_reader :status_code, :response_body, :response_headers
|
6
|
+
|
7
|
+
def initialize(response)
|
8
|
+
@status_code = response['code']
|
9
|
+
@response_body = response['body']
|
10
|
+
@response_headers = response['headers']
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class MockRequest < SendGrid::Client
|
15
|
+
def make_request(_http, _request)
|
16
|
+
response = {}
|
17
|
+
response['code'] = 200
|
18
|
+
response['body'] = { 'message' => 'success' }
|
19
|
+
response['headers'] = { 'headers' => 'test' }
|
20
|
+
MockResponse.new(response)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TestClient < Minitest::Test
|
25
|
+
def setup
|
26
|
+
@headers = JSON.parse('
|
27
|
+
{
|
28
|
+
"Authorization": "Bearer XXXXXXX",
|
29
|
+
"Content-Type": "application/json"
|
30
|
+
}
|
31
|
+
')
|
32
|
+
@host = 'http://localhost:4010'
|
33
|
+
@version = 'v3'
|
34
|
+
@client = MockRequest.new(host: @host,
|
35
|
+
request_headers: @headers,
|
36
|
+
version: @version)
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_init
|
40
|
+
assert_equal(@host, @client.host)
|
41
|
+
assert_equal(@headers, @client.request_headers)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_update_headers
|
45
|
+
request_headers = { 'X-Test' => 'test' }
|
46
|
+
@client.update_headers(request_headers)
|
47
|
+
assert_equal(@headers.merge(request_headers), @client.request_headers)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_build_request_headers
|
51
|
+
request = {}
|
52
|
+
request = @client.build_request_headers(request)
|
53
|
+
assert_equal(@client.request_headers, request)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_add_version
|
57
|
+
url = ''
|
58
|
+
@client.add_version(url)
|
59
|
+
assert_equal(url, "/#{@version}")
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_build_query_params
|
63
|
+
url = ''
|
64
|
+
query_params = { 'limit' => 100, 'offset' => 0 }
|
65
|
+
url = @client.build_query_params(url, query_params)
|
66
|
+
assert_equal(url, '?limit=100&offset=0')
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_build_url
|
70
|
+
url1 = @client.my.path.to.the.endpoint
|
71
|
+
params = { 'limit' => 100, 'offset' => 0 }
|
72
|
+
url = URI.parse(@host + '/' + @version +
|
73
|
+
'/my/path/to/the/endpoint?limit=100&offset=0')
|
74
|
+
assert_equal(url1.build_url(query_params: params), url)
|
75
|
+
|
76
|
+
url1 = url1.one_more
|
77
|
+
params = { 'limit' => 100, 'offset' => 0 }
|
78
|
+
url = URI.parse(@host + '/' + @version +
|
79
|
+
'/my/path/to/the/endpoint/one_more?limit=100&offset=0')
|
80
|
+
assert_equal(url1.build_url(query_params: params), url)
|
81
|
+
|
82
|
+
url2 = @client.my.path._('to').the.endpoint
|
83
|
+
params = { 'limit' => 100, 'offset' => 0 }
|
84
|
+
url = URI.parse(@host + '/' + @version +
|
85
|
+
'/my/path/to/the/endpoint?limit=100&offset=0')
|
86
|
+
assert_equal(url2.build_url(query_params: params), url)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_build_request
|
90
|
+
name = 'get'
|
91
|
+
args = nil
|
92
|
+
response = @client.build_request(name, args)
|
93
|
+
assert_equal(response.status_code, 200)
|
94
|
+
assert_equal(response.response_body, 'message' => 'success')
|
95
|
+
assert_equal(response.response_headers, 'headers' => 'test')
|
96
|
+
end
|
97
|
+
|
98
|
+
def add_ssl
|
99
|
+
uri = URI.parse('https://localhost:4010')
|
100
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
101
|
+
http = @client.add_ssl(http)
|
102
|
+
assert_equal(http.use_ssl, true)
|
103
|
+
assert_equal(http.verify_mode, OpenSSL::SSL::VERIFY_NONE)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test__
|
107
|
+
url1 = @client._('test')
|
108
|
+
assert_equal(url1.url_path, ['test'])
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_method_missing
|
112
|
+
response = @client.get
|
113
|
+
assert_equal(response.status_code, 200)
|
114
|
+
assert_equal(response.response_body, 'message' => 'success')
|
115
|
+
assert_equal(response.response_headers, 'headers' => 'test')
|
116
|
+
end
|
117
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby_http_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Elmer Thomas
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
description: Quickly and easily access any REST or REST-like API.
|
42
|
+
email: dx@sendgrid.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- ".env_sample"
|
48
|
+
- ".github/ISSUE_TEMPLATE"
|
49
|
+
- ".gitignore"
|
50
|
+
- ".travis.yml"
|
51
|
+
- CHANGELOG.md
|
52
|
+
- CONTRIBUTING.md
|
53
|
+
- LICENSE
|
54
|
+
- README.md
|
55
|
+
- Rakefile
|
56
|
+
- examples/example.rb
|
57
|
+
- lib/config.rb
|
58
|
+
- lib/ruby_http_client.rb
|
59
|
+
- ruby_http_client.gemspec
|
60
|
+
- test/test_ruby_http_client.rb
|
61
|
+
homepage: http://github.com/sendgrid/ruby-http-client
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.4.8
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: A simple REST client
|
85
|
+
test_files:
|
86
|
+
- test/test_ruby_http_client.rb
|