wordpress_client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.hound.yml +2 -0
- data/.rubocop.yml +1065 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/Guardfile +29 -0
- data/LICENSE +21 -0
- data/README.md +63 -0
- data/Rakefile +1 -0
- data/circle.yml +3 -0
- data/lib/wordpress_client.rb +25 -0
- data/lib/wordpress_client/category.rb +4 -0
- data/lib/wordpress_client/client.rb +142 -0
- data/lib/wordpress_client/connection.rb +186 -0
- data/lib/wordpress_client/errors.rb +10 -0
- data/lib/wordpress_client/media.rb +37 -0
- data/lib/wordpress_client/media_parser.rb +48 -0
- data/lib/wordpress_client/paginated_collection.rb +53 -0
- data/lib/wordpress_client/post.rb +62 -0
- data/lib/wordpress_client/post_parser.rb +113 -0
- data/lib/wordpress_client/replace_metadata.rb +81 -0
- data/lib/wordpress_client/replace_terms.rb +62 -0
- data/lib/wordpress_client/rest_parser.rb +17 -0
- data/lib/wordpress_client/tag.rb +4 -0
- data/lib/wordpress_client/term.rb +34 -0
- data/lib/wordpress_client/version.rb +3 -0
- data/spec/category_spec.rb +8 -0
- data/spec/client_spec.rb +411 -0
- data/spec/connection_spec.rb +270 -0
- data/spec/docker/Dockerfile +40 -0
- data/spec/docker/README.md +37 -0
- data/spec/docker/dbdump.sql.gz +0 -0
- data/spec/docker/htaccess +10 -0
- data/spec/docker/restore-dbdump.sh +13 -0
- data/spec/fixtures/category.json +1 -0
- data/spec/fixtures/image-media.json +1 -0
- data/spec/fixtures/invalid-post-id.json +1 -0
- data/spec/fixtures/post-with-forbidden-metadata.json +1 -0
- data/spec/fixtures/post-with-metadata.json +1 -0
- data/spec/fixtures/simple-post.json +1 -0
- data/spec/fixtures/tag.json +1 -0
- data/spec/fixtures/thoughtful.jpg +0 -0
- data/spec/fixtures/validation-error.json +1 -0
- data/spec/integration/attachments_crud_spec.rb +51 -0
- data/spec/integration/categories_spec.rb +60 -0
- data/spec/integration/category_assignment_spec.rb +29 -0
- data/spec/integration/posts_crud_spec.rb +118 -0
- data/spec/integration/posts_finding_spec.rb +86 -0
- data/spec/integration/posts_metadata_spec.rb +27 -0
- data/spec/integration/posts_with_attachments_spec.rb +21 -0
- data/spec/integration/tag_assignment_spec.rb +29 -0
- data/spec/integration/tags_spec.rb +36 -0
- data/spec/media_spec.rb +63 -0
- data/spec/paginated_collection_spec.rb +64 -0
- data/spec/post_spec.rb +114 -0
- data/spec/replace_metadata_spec.rb +56 -0
- data/spec/replace_terms_spec.rb +51 -0
- data/spec/shared_examples/term_examples.rb +37 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/docker_runner.rb +49 -0
- data/spec/support/fixtures.rb +19 -0
- data/spec/support/integration_macros.rb +10 -0
- data/spec/support/wordpress_server.rb +103 -0
- data/spec/tag_spec.rb +8 -0
- data/wordpress_client.gemspec +27 -0
- metadata +219 -0
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.2
|
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
rspec_options = {
|
2
|
+
cmd: 'rspec -f documentation -t focus',
|
3
|
+
failed_mode: :keep,
|
4
|
+
all_after_pass: true,
|
5
|
+
all_on_start: true,
|
6
|
+
run_all: {cmd: 'rspec -f progress -t focus'}
|
7
|
+
}
|
8
|
+
|
9
|
+
guard :rspec, rspec_options do
|
10
|
+
require "guard/rspec/dsl"
|
11
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
12
|
+
|
13
|
+
# RSpec files
|
14
|
+
rspec = dsl.rspec
|
15
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
16
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
17
|
+
watch(rspec.spec_files)
|
18
|
+
|
19
|
+
watch("spec/shared_examples/term_examples.rb") do
|
20
|
+
[
|
21
|
+
"spec/category_spec.rb",
|
22
|
+
"spec/tag_spec.rb",
|
23
|
+
]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Ruby files
|
27
|
+
watch("lib/wordpress_client.rb") { rspec.spec_dir }
|
28
|
+
dsl.watch_spec_files_for(%r{^lib/wordpress_client/(.*)\.rb$})
|
29
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Hemnet
|
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,63 @@
|
|
1
|
+
# WordpressClient
|
2
|
+
|
3
|
+
WordpressClient is a very simple client to the Wordpress API, version 2 beta 8.0.
|
4
|
+
|
5
|
+
**NOTE:** The repository is still named `wpclient` as we're in the middle of a rename. Some references might persist until it's completed.
|
6
|
+
|
7
|
+
[![Circle CI](https://circleci.com/gh/hemnet/wpclient.svg?style=svg)](https://circleci.com/gh/hemnet/wpclient) [![Code Climate](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/gpa.svg)](https://codeclimate.com/repos/5645938269568041da00cded/feed) [![Test Coverage](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/coverage.svg)](https://codeclimate.com/repos/5645938269568041da00cded/coverage)
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Initialize a client with a username, password and API URL. You can then search for posts.
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
client = WordpressClient.new(url: "https://example.com/wp-json/", username: "example", password: "example")
|
15
|
+
|
16
|
+
client.posts(per_page: 5) # => [WordpressClient::Post, WordpressClient::Post]
|
17
|
+
```
|
18
|
+
|
19
|
+
### Creating a post
|
20
|
+
|
21
|
+
You can create posts by calling `create_post`. If you supply a ID, the article will be created using `PUT` instead of `POST`.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
data = {
|
25
|
+
author: "Name",
|
26
|
+
# ...
|
27
|
+
}
|
28
|
+
|
29
|
+
post = client.create_post(data) # => WordpressClient::Post
|
30
|
+
updated_post = client.update_post(post.id, title: "Updated") # => WordpressClient::Post
|
31
|
+
|
32
|
+
updated_post.title_html # => "Updated"
|
33
|
+
```
|
34
|
+
|
35
|
+
## Running tests
|
36
|
+
|
37
|
+
You need to install Docker and set it up for your machine. Note that you need `docker-machine` to run Docker on OS X.
|
38
|
+
|
39
|
+
Run tests using the normal `rspec` command after installing all bundles. The first time the integration tests are run, a docker image will be built that hosts a Wordpress installation, but the image will be re-used on subsequent runs.
|
40
|
+
|
41
|
+
```
|
42
|
+
bundle exec rspec
|
43
|
+
```
|
44
|
+
|
45
|
+
You can also run `bundle exec guard` to have tests run automatically when you change files in the repo. If you tag your examples with `focus: true`, Guard will only run those tests. This can help when doing very focused coding, but remember to remove the filter before you commit and let the entire suite run.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
describe Foo, focus: true do
|
49
|
+
# ...
|
50
|
+
end
|
51
|
+
```
|
52
|
+
|
53
|
+
The normal `rspec` command will *not* use this filter in case it is ever committed accidentally, so CI can catch any problems.
|
54
|
+
|
55
|
+
## Copyright & License
|
56
|
+
|
57
|
+
Copyright © 2015 Hemnet Service HNS AB
|
58
|
+
|
59
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
60
|
+
|
61
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
62
|
+
|
63
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/circle.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "wordpress_client/version"
|
2
|
+
require "wordpress_client/errors"
|
3
|
+
|
4
|
+
require "wordpress_client/rest_parser"
|
5
|
+
require "wordpress_client/connection"
|
6
|
+
require "wordpress_client/client"
|
7
|
+
require "wordpress_client/paginated_collection"
|
8
|
+
|
9
|
+
require "wordpress_client/term"
|
10
|
+
require "wordpress_client/category"
|
11
|
+
require "wordpress_client/tag"
|
12
|
+
|
13
|
+
require "wordpress_client/post"
|
14
|
+
require "wordpress_client/post_parser"
|
15
|
+
require "wordpress_client/media"
|
16
|
+
require "wordpress_client/media_parser"
|
17
|
+
|
18
|
+
require "wordpress_client/replace_terms"
|
19
|
+
require "wordpress_client/replace_metadata"
|
20
|
+
|
21
|
+
module WordpressClient
|
22
|
+
def self.new(*args)
|
23
|
+
Client.new(Connection.new(*args))
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module WordpressClient
|
2
|
+
class Client
|
3
|
+
def initialize(connection)
|
4
|
+
@connection = connection
|
5
|
+
end
|
6
|
+
|
7
|
+
def posts(per_page: 10, page: 1, category_slug: nil, tag_slug: nil)
|
8
|
+
filter = {}
|
9
|
+
filter[:category_name] = category_slug if category_slug
|
10
|
+
filter[:tag] = tag_slug if tag_slug
|
11
|
+
connection.get_multiple(
|
12
|
+
Post, "posts", per_page: per_page, page: page, _embed: nil, context: "edit", filter: filter
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def categories(per_page: 10, page: 1)
|
17
|
+
connection.get_multiple(Category, "terms/category", page: page, per_page: per_page)
|
18
|
+
end
|
19
|
+
|
20
|
+
def tags(per_page: 10, page: 1)
|
21
|
+
connection.get_multiple(Tag, "terms/tag", page: page, per_page: per_page)
|
22
|
+
end
|
23
|
+
|
24
|
+
def media(per_page: 10, page: 1)
|
25
|
+
connection.get_multiple(Media, "media", page: page, per_page: per_page)
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_post(id)
|
29
|
+
connection.get(Post, "posts/#{id.to_i}", _embed: nil, context: "edit")
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_by_slug(slug)
|
33
|
+
posts = connection.get_multiple(
|
34
|
+
Post, "posts", per_page: 1, page: 1, filter: {name: slug}, _embed: nil
|
35
|
+
)
|
36
|
+
if posts.size > 0
|
37
|
+
posts.first
|
38
|
+
else
|
39
|
+
raise NotFoundError, "Could not find post with slug #{slug.to_s.inspect}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_category(id)
|
44
|
+
connection.get(Category, "terms/category/#{id.to_i}")
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_tag(id)
|
48
|
+
connection.get(Tag, "terms/tag/#{id.to_i}")
|
49
|
+
end
|
50
|
+
|
51
|
+
def find_media(id)
|
52
|
+
connection.get(Media, "media/#{id.to_i}")
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_post(attributes)
|
56
|
+
post = connection.create(Post, "posts", attributes, redirect_params: {_embed: nil})
|
57
|
+
|
58
|
+
changes = 0
|
59
|
+
changes += assign_meta(post, attributes[:meta])
|
60
|
+
changes += assign_categories(post, attributes[:category_ids])
|
61
|
+
changes += assign_tags(post, attributes[:tag_ids])
|
62
|
+
|
63
|
+
if changes > 0
|
64
|
+
find_post(post.id)
|
65
|
+
else
|
66
|
+
post
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_category(attributes)
|
71
|
+
connection.create(Category, "terms/category", attributes)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_tag(attributes)
|
75
|
+
connection.create(Tag, "terms/tag", attributes)
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_post(id, attributes)
|
79
|
+
post = connection.patch(Post, "posts/#{id.to_i}?_embed", attributes)
|
80
|
+
|
81
|
+
changes = 0
|
82
|
+
changes += assign_meta(post, attributes[:meta])
|
83
|
+
changes += assign_categories(post, attributes[:category_ids])
|
84
|
+
changes += assign_tags(post, attributes[:tag_ids])
|
85
|
+
|
86
|
+
if changes > 0
|
87
|
+
find_post(post.id)
|
88
|
+
else
|
89
|
+
post
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_category(id, attributes)
|
94
|
+
connection.patch(Category, "terms/category/#{id.to_i}", attributes)
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_tag(id, attributes)
|
98
|
+
connection.patch(Tag, "terms/tag/#{id.to_i}", attributes)
|
99
|
+
end
|
100
|
+
|
101
|
+
def update_media(id, attributes)
|
102
|
+
connection.patch(Media, "media/#{id.to_i}", attributes)
|
103
|
+
end
|
104
|
+
|
105
|
+
def upload(io, mime_type:, filename:)
|
106
|
+
connection.upload(Media, "media", io, mime_type: mime_type, filename: filename)
|
107
|
+
end
|
108
|
+
|
109
|
+
def upload_file(filename, mime_type:)
|
110
|
+
path = filename.to_s
|
111
|
+
File.open(path, 'r') do |file|
|
112
|
+
upload(file, mime_type: mime_type, filename: File.basename(path))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete_post(id, force: false)
|
117
|
+
connection.delete("posts/#{id.to_i}", {"force" => force})
|
118
|
+
end
|
119
|
+
|
120
|
+
def inspect
|
121
|
+
"#<WordpressClient::Client #{connection.inspect}>"
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
attr_reader :connection
|
126
|
+
|
127
|
+
def assign_categories(post, ids)
|
128
|
+
return 0 unless ids
|
129
|
+
ReplaceTerms.apply_categories(connection, post, ids)
|
130
|
+
end
|
131
|
+
|
132
|
+
def assign_tags(post, ids)
|
133
|
+
return 0 unless ids
|
134
|
+
ReplaceTerms.apply_tags(connection, post, ids)
|
135
|
+
end
|
136
|
+
|
137
|
+
def assign_meta(post, meta)
|
138
|
+
return 0 unless meta
|
139
|
+
ReplaceMetadata.apply(connection, post, meta)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module WordpressClient
|
5
|
+
class Connection
|
6
|
+
attr_reader :url, :username
|
7
|
+
|
8
|
+
def initialize(url:, username:, password:)
|
9
|
+
@url = url
|
10
|
+
@username = username
|
11
|
+
@password = password
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(model, path, params = {})
|
15
|
+
model.parse(get_json(path, params))
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_multiple(model, path, params = {})
|
19
|
+
data, response = get_json_and_response(path, params)
|
20
|
+
models = data.map { |model_data| model.parse(model_data) }
|
21
|
+
wrap_paginated_collection(response, models, params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create(model, path, attributes, redirect_params: {})
|
25
|
+
response = send_json(path, attributes)
|
26
|
+
|
27
|
+
if response.status == 201 # Created
|
28
|
+
model.parse(get_json(response.headers.fetch("location"), redirect_params))
|
29
|
+
else
|
30
|
+
handle_status_code(response)
|
31
|
+
model.parse(parse_json_response(response))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def create_without_response(path, attributes)
|
36
|
+
response = send_json(path, attributes)
|
37
|
+
|
38
|
+
if response.status == 201 # Created
|
39
|
+
true
|
40
|
+
else
|
41
|
+
handle_status_code(response)
|
42
|
+
true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete(path, attributes = {})
|
47
|
+
response = send_json(path, attributes, method: :delete)
|
48
|
+
handle_status_code(response)
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
def patch(model, path, attributes)
|
53
|
+
model.parse(
|
54
|
+
parse_json_response(send_json(path, attributes, method: :patch))
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
def patch_without_response(path, attributes)
|
59
|
+
handle_status_code(send_json(path, attributes, method: :patch))
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def upload(model, path, io, mime_type:, filename:)
|
64
|
+
body = io.read
|
65
|
+
response = post_data(path, body, {
|
66
|
+
"Content-Length" => body.size.to_s,
|
67
|
+
"Content-Type" => mime_type,
|
68
|
+
# WP API does not parse normal Content-Disposition and instead ops to using their own format
|
69
|
+
# https://github.com/WP-API/WP-API/issues/1744
|
70
|
+
"Content-Disposition" => "filename=#{filename || "unnamed"}",
|
71
|
+
})
|
72
|
+
|
73
|
+
if response.status == 201 # Created
|
74
|
+
model.parse(get_json(response.headers.fetch("location")))
|
75
|
+
else
|
76
|
+
handle_status_code(response)
|
77
|
+
model.parse(parse_json_response(response))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def inspect
|
82
|
+
"#<#{self.class.name} #@username @ #@url>"
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
def net
|
87
|
+
@net ||= setup_network_connection
|
88
|
+
end
|
89
|
+
|
90
|
+
def setup_network_connection
|
91
|
+
Faraday.new(url: "#{url}/wp/v2") do |conn|
|
92
|
+
conn.request :basic_auth, username, @password
|
93
|
+
conn.adapter :net_http
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def wrap_paginated_collection(response, entries, params)
|
98
|
+
total = response.headers.fetch("x-wp-total").to_i
|
99
|
+
current_page = params.fetch(:page).to_i
|
100
|
+
per_page = params.fetch(:per_page).to_i
|
101
|
+
|
102
|
+
PaginatedCollection.new(
|
103
|
+
entries, total: total, current_page: current_page, per_page: per_page
|
104
|
+
)
|
105
|
+
end
|
106
|
+
|
107
|
+
def get_json(path, params = {})
|
108
|
+
get_json_and_response(path, params).first
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_json_and_response(path, params = {})
|
112
|
+
response = net.get(path, params)
|
113
|
+
[parse_json_response(response), response]
|
114
|
+
rescue Faraday::TimeoutError
|
115
|
+
raise TimeoutError
|
116
|
+
end
|
117
|
+
|
118
|
+
def send_json(path, data, method: :post)
|
119
|
+
unless %i[get post put patch delete].include? method
|
120
|
+
raise ArgumentError, "Invalid method: #{method.inspect}"
|
121
|
+
end
|
122
|
+
|
123
|
+
net.public_send(method) do |request|
|
124
|
+
json = data.to_json
|
125
|
+
request.url path
|
126
|
+
request.headers["Content-Type"] = "application/json; charset=#{json.encoding}"
|
127
|
+
request.body = json
|
128
|
+
end
|
129
|
+
rescue Faraday::TimeoutError
|
130
|
+
raise TimeoutError
|
131
|
+
end
|
132
|
+
|
133
|
+
def post_data(path, data, headers)
|
134
|
+
net.post do |request|
|
135
|
+
request.url path
|
136
|
+
request.headers = headers
|
137
|
+
request.body = data
|
138
|
+
end
|
139
|
+
rescue Faraday::TimeoutError
|
140
|
+
raise TimeoutError
|
141
|
+
end
|
142
|
+
|
143
|
+
def parse_json_response(response)
|
144
|
+
handle_status_code(response)
|
145
|
+
|
146
|
+
content_type = response.headers["content-type"].split(";").first
|
147
|
+
unless content_type == "application/json"
|
148
|
+
raise ServerError, "Got content type #{content_type}"
|
149
|
+
end
|
150
|
+
|
151
|
+
JSON.parse(response.body)
|
152
|
+
|
153
|
+
rescue JSON::ParserError => error
|
154
|
+
raise ServerError, "Could not parse JSON response: #{error}"
|
155
|
+
end
|
156
|
+
|
157
|
+
def handle_status_code(response)
|
158
|
+
case response.status
|
159
|
+
when 200
|
160
|
+
return
|
161
|
+
when 404
|
162
|
+
raise NotFoundError, "Could not find resource"
|
163
|
+
when 400
|
164
|
+
handle_bad_request(response)
|
165
|
+
else
|
166
|
+
raise ServerError, "Server returned status code #{response.status}: #{response.body}"
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def handle_bad_request(response)
|
171
|
+
code, message = bad_request_details(response)
|
172
|
+
if code == "rest_post_invalid_id"
|
173
|
+
raise NotFoundError, "Post ID is not found"
|
174
|
+
else
|
175
|
+
raise ValidationError, message
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def bad_request_details(response)
|
180
|
+
details = JSON.parse(response.body)
|
181
|
+
[details["code"], details["message"]]
|
182
|
+
rescue
|
183
|
+
[nil, "Bad Request"]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|