dawarich/spec/swagger/api/v1/places_controller_spec.rb
2025-11-22 19:45:53 +01:00

332 lines
11 KiB
Ruby

# frozen_string_literal: true
require 'swagger_helper'
RSpec.describe 'Places API', type: :request do
path '/api/v1/places' do
get 'Retrieves all places for the authenticated user' do
tags 'Places'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
parameter name: :tag_ids, in: :query, type: :array, items: { type: :integer }, required: false, description: 'Filter places by tag IDs'
response '200', 'places found' do
schema type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
source: { type: :string },
icon: { type: :string, nullable: true },
color: { type: :string, nullable: true },
visits_count: { type: :integer },
created_at: { type: :string, format: 'date-time' },
tags: {
type: :array,
items: {
type: :object,
properties: {
id: { type: :integer },
name: { type: :string },
icon: { type: :string },
color: { type: :string }
}
}
}
},
required: %w[id name latitude longitude]
}
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let!(:place) { create(:place, user: user) }
run_test! do |response|
data = JSON.parse(response.body)
expect(data).to be_an(Array)
expect(data.first['id']).to eq(place.id)
end
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
run_test!
end
end
post 'Creates a place' do
tags 'Places'
consumes 'application/json'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
parameter name: :place, in: :body, schema: {
type: :object,
properties: {
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
source: { type: :string },
tag_ids: { type: :array, items: { type: :integer } }
},
required: %w[name latitude longitude]
}
response '201', 'place created' do
schema type: :object,
properties: {
id: { type: :integer },
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
source: { type: :string },
icon: { type: :string, nullable: true },
color: { type: :string, nullable: true },
visits_count: { type: :integer },
created_at: { type: :string, format: 'date-time' },
tags: { type: :array }
}
let(:user) { create(:user) }
let(:tag) { create(:tag, user: user) }
let(:api_key) { user.api_key }
let(:place) do
{
name: 'Coffee Shop',
latitude: 40.7589,
longitude: -73.9851,
source: 'manual',
tag_ids: [tag.id]
}
end
run_test! do |response|
data = JSON.parse(response.body)
expect(data['name']).to eq('Coffee Shop')
# Note: tags array is expected to be in the response schema but may be empty initially
# Tags can be added separately via the update endpoint
expect(data).to have_key('tags')
end
end
response '422', 'invalid request' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:place) { { name: '' } }
run_test!
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
let(:place) { { name: 'Test', latitude: 40.0, longitude: -73.0 } }
run_test!
end
end
end
path '/api/v1/places/nearby' do
get 'Searches for nearby places using Photon geocoding API' do
tags 'Places'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
parameter name: :latitude, in: :query, type: :number, format: :float, required: true, description: 'Latitude coordinate'
parameter name: :longitude, in: :query, type: :number, format: :float, required: true, description: 'Longitude coordinate'
parameter name: :radius, in: :query, type: :number, format: :float, required: false, description: 'Search radius in kilometers (default: 0.5)'
parameter name: :limit, in: :query, type: :integer, required: false, description: 'Maximum number of results (default: 10)'
response '200', 'nearby places found' do
schema type: :object,
properties: {
places: {
type: :array,
items: {
type: :object,
properties: {
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
distance: { type: :number, format: :float },
type: { type: :string }
}
}
}
}
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:latitude) { 40.7589 }
let(:longitude) { -73.9851 }
let(:radius) { 1.0 }
let(:limit) { 5 }
run_test! do |response|
data = JSON.parse(response.body)
expect(data).to have_key('places')
expect(data['places']).to be_an(Array)
end
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
let(:latitude) { 40.7589 }
let(:longitude) { -73.9851 }
run_test!
end
end
end
path '/api/v1/places/{id}' do
parameter name: :id, in: :path, type: :integer, description: 'Place ID'
get 'Retrieves a specific place' do
tags 'Places'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
response '200', 'place found' do
schema type: :object,
properties: {
id: { type: :integer },
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
source: { type: :string },
icon: { type: :string, nullable: true },
color: { type: :string, nullable: true },
visits_count: { type: :integer },
created_at: { type: :string, format: 'date-time' },
tags: { type: :array }
}
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:place) { create(:place, user: user) }
let(:id) { place.id }
run_test! do |response|
data = JSON.parse(response.body)
expect(data['id']).to eq(place.id)
end
end
response '404', 'place not found' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:id) { 'invalid' }
run_test!
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
let(:place) { create(:place) }
let(:id) { place.id }
run_test!
end
end
patch 'Updates a place' do
tags 'Places'
consumes 'application/json'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
parameter name: :place, in: :body, schema: {
type: :object,
properties: {
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
tag_ids: { type: :array, items: { type: :integer } }
}
}
response '200', 'place updated' do
schema type: :object,
properties: {
id: { type: :integer },
name: { type: :string },
latitude: { type: :number, format: :float },
longitude: { type: :number, format: :float },
tags: { type: :array }
}
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:existing_place) { create(:place, user: user) }
let(:id) { existing_place.id }
let(:place) { { name: 'Updated Name' } }
run_test! do |response|
data = JSON.parse(response.body)
expect(data['name']).to eq('Updated Name')
end
end
response '404', 'place not found' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:id) { 'invalid' }
let(:place) { { name: 'Updated' } }
run_test!
end
response '422', 'invalid request' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:existing_place) { create(:place, user: user) }
let(:id) { existing_place.id }
let(:place) { { name: '' } }
run_test!
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
let(:existing_place) { create(:place) }
let(:id) { existing_place.id }
let(:place) { { name: 'Updated' } }
run_test!
end
end
delete 'Deletes a place' do
tags 'Places'
produces 'application/json'
parameter name: :api_key, in: :query, type: :string, required: true, description: 'API key for authentication'
response '204', 'place deleted' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:place) { create(:place, user: user) }
let(:id) { place.id }
run_test!
end
response '404', 'place not found' do
let(:user) { create(:user) }
let(:api_key) { user.api_key }
let(:id) { 'invalid' }
run_test!
end
response '401', 'unauthorized' do
let(:api_key) { 'invalid' }
let(:place) { create(:place) }
let(:id) { place.id }
run_test!
end
end
end
end