Skip to content

Commit caeb0c8

Browse files
committed
added support for delete resource in sdk
1 parent 9862c39 commit caeb0c8

File tree

19 files changed

+383
-413
lines changed

19 files changed

+383
-413
lines changed

golang/README.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,18 +122,51 @@ package main
122122
import (
123123
"context"
124124
"fmt"
125+
"log"
125126
"github.com/melvinodsa/go-iam-sdk/golang"
126127
)
127128

128129
func main() {
129-
service := golang.NewService("https://your-iam-api.com", "username", "password")
130+
// Initialize the service
131+
service := golang.NewService("https://your-iam-api.com", "client-id", "secret")
132+
ctx := context.Background()
130133

131134
// Verify authentication code
132-
result, err := service.Verify(context.Background(), "auth-code")
135+
token, err := service.Verify(ctx, "auth-code")
133136
if err != nil {
134-
panic(err)
137+
log.Fatalf("Failed to verify code: %v", err)
135138
}
139+
fmt.Printf("Access Token: %s\n", token)
136140

137-
fmt.Printf("Verification result: %+v\n", result)
141+
// Get current user information
142+
user, err := service.Me(ctx, token)
143+
if err != nil {
144+
log.Fatalf("Failed to fetch user: %v", err)
145+
}
146+
fmt.Printf("User: %s (%s)\n", user.Name, user.Email)
147+
148+
// Create a resource
149+
resource := &golang.Resource{
150+
Name: "Test Resource",
151+
Description: "A test resource",
152+
Key: "test-key",
153+
Enabled: true,
154+
ProjectId: "project-123",
155+
CreatedBy: "admin",
156+
UpdatedBy: "admin",
157+
}
158+
159+
err = service.CreateResource(ctx, resource, token)
160+
if err != nil {
161+
log.Fatalf("Failed to create resource: %v", err)
162+
}
163+
fmt.Println("Resource created successfully")
164+
165+
// Delete a resource
166+
err = service.DeleteResource(ctx, "resource-id", token)
167+
if err != nil {
168+
log.Fatalf("Failed to delete resource: %v", err)
169+
}
170+
fmt.Println("Resource deleted successfully")
138171
}
139172
```

golang/service.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ type Service interface {
66
Verify(ctx context.Context, code string) (string, error)
77
Me(ctx context.Context, token string) (*User, error)
88
CreateResource(ctx context.Context, resource *Resource, token string) error
9+
DeleteResource(ctx context.Context, resourceID string, token string) error
910
}

golang/service_impl.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,39 @@ func (s *serviceImpl) CreateResource(ctx context.Context, resource *Resource, to
134134

135135
return nil
136136
}
137+
138+
// DeleteResource deletes a resource with the provided ID and token.
139+
// It returns an error if the deletion fails.
140+
func (s *serviceImpl) DeleteResource(ctx context.Context, resourceID string, token string) error {
141+
url := fmt.Sprintf("%s/resource/v1/%s", s.baseURL, resourceID)
142+
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, url, nil)
143+
if err != nil {
144+
return fmt.Errorf("error creating request: %w", err)
145+
}
146+
147+
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
148+
resp, err := http.DefaultClient.Do(req)
149+
if err != nil {
150+
return fmt.Errorf("error making request: %w", err)
151+
}
152+
defer resp.Body.Close()
153+
154+
var statusError error
155+
if resp.StatusCode != http.StatusOK {
156+
statusError = fmt.Errorf("failed to delete resource: %s", resp.Status)
157+
}
158+
159+
result := ResourceResponse{}
160+
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
161+
if statusError != nil {
162+
return fmt.Errorf("%w: %s", statusError, err)
163+
}
164+
return fmt.Errorf("error decoding response: %w", err)
165+
}
166+
167+
if !result.Success {
168+
return fmt.Errorf("failed to delete resource: %s. Status: %s", result.Message, resp.Status)
169+
}
170+
171+
return nil
172+
}

golang/service_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,51 @@ func TestCreateResource(t *testing.T) {
115115
}
116116
})
117117
}
118+
119+
func TestDeleteResource(t *testing.T) {
120+
handler := func(w http.ResponseWriter, r *http.Request) {
121+
if r.Header.Get("Authorization") == "Bearer valid-token" {
122+
w.WriteHeader(http.StatusOK)
123+
w.Write([]byte(`{"success":true,"message":"Resource deleted successfully"}`))
124+
} else {
125+
w.WriteHeader(http.StatusUnauthorized)
126+
w.Write([]byte(`{"success":false,"message":"Invalid token"}`))
127+
}
128+
}
129+
130+
ts := httptest.NewServer(http.HandlerFunc(handler))
131+
defer ts.Close()
132+
133+
service := NewService(ts.URL, "client-id", "secret")
134+
135+
t.Run("Valid Token", func(t *testing.T) {
136+
err := service.DeleteResource(context.Background(), "resource-123", "valid-token")
137+
if err != nil {
138+
t.Fatalf("expected no error, got %v", err)
139+
}
140+
})
141+
142+
t.Run("Invalid Token", func(t *testing.T) {
143+
err := service.DeleteResource(context.Background(), "resource-123", "invalid-token")
144+
if err == nil {
145+
t.Fatal("expected an error, got none")
146+
}
147+
})
148+
149+
t.Run("Non-existent Resource", func(t *testing.T) {
150+
// Override handler for this test to return 404
151+
notFoundHandler := func(w http.ResponseWriter, r *http.Request) {
152+
w.WriteHeader(http.StatusNotFound)
153+
w.Write([]byte(`{"success":false,"message":"Resource not found"}`))
154+
}
155+
156+
notFoundServer := httptest.NewServer(http.HandlerFunc(notFoundHandler))
157+
defer notFoundServer.Close()
158+
159+
notFoundService := NewService(notFoundServer.URL, "client-id", "secret")
160+
err := notFoundService.DeleteResource(context.Background(), "non-existent", "valid-token")
161+
if err == nil {
162+
t.Fatal("expected an error, got none")
163+
}
164+
})
165+
}

python/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,16 @@ except Exception as error:
7272
print(f"Failed to create resource: {error}")
7373
```
7474

75+
### Delete a Resource
76+
77+
```python
78+
try:
79+
service.delete_resource("resource-id", token)
80+
print("Resource deleted successfully")
81+
except Exception as error:
82+
print(f"Failed to delete resource: {error}")
83+
```
84+
7585
## Classes
7686

7787
The SDK provides the following main classes:

python/goiam/service.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,17 @@ def create_resource(self, resource: Resource, token: str) -> None:
5151
Exception: If creation fails
5252
"""
5353
pass
54+
55+
@abstractmethod
56+
def delete_resource(self, resource_id: str, token: str) -> None:
57+
"""
58+
Delete a resource by ID
59+
60+
Args:
61+
resource_id: ID of the resource to delete
62+
token: Bearer token for authentication
63+
64+
Raises:
65+
Exception: If deletion fails
66+
"""
67+
pass

python/goiam/service_impl.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,40 @@ def create_resource(self, resource: Resource, token: str) -> None:
140140
except Exception as e:
141141
raise Exception(f"Failed to create resource: {str(e)}")
142142

143+
def delete_resource(self, resource_id: str, token: str) -> None:
144+
"""
145+
Delete a resource by ID
146+
147+
Args:
148+
resource_id: ID of the resource to delete
149+
token: Bearer token for authentication
150+
151+
Raises:
152+
Exception: If deletion fails
153+
"""
154+
url = f"{self.base_url}/resource/v1/{resource_id}"
155+
headers = {"Authorization": f"Bearer {token}"}
156+
157+
try:
158+
response = self.session.delete(url, headers=headers)
159+
160+
if response.status_code != 200:
161+
raise Exception(
162+
f"Failed to delete resource: {response.status_code} {response.reason}"
163+
)
164+
165+
resource_response = ResourceResponse(response.json())
166+
167+
if not resource_response.success:
168+
raise Exception(
169+
f"Failed to delete resource: {resource_response.message}"
170+
)
171+
172+
except requests.RequestException as e:
173+
raise Exception(f"Request failed: {str(e)}")
174+
except Exception as e:
175+
raise Exception(f"Failed to delete resource: {str(e)}")
176+
143177

144178
def new_service(base_url: str, client_id: str, secret: str) -> Service:
145179
"""

python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "goiam-python"
7-
version = "0.2.0"
7+
version = "0.3.0"
88
description = "Python SDK for Go IAM - A lightweight Identity and Access Management server"
99
readme = "README.md"
1010
license = { file = "LICENSE" }

python/test_service.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,47 @@ def test_create_resource_failure(self, mock_post):
107107

108108
self.assertIn("Failed to create resource", str(context.exception))
109109

110+
@patch("goiam.service_impl.requests.Session.delete")
111+
def test_delete_resource_success(self, mock_delete):
112+
# Mock successful response
113+
mock_response = Mock()
114+
mock_response.status_code = 200
115+
mock_response.json.return_value = {
116+
"success": True,
117+
"message": "Resource deleted successfully",
118+
}
119+
mock_delete.return_value = mock_response
120+
121+
# Should not raise an exception
122+
self.service.delete_resource("resource-123", "valid-token")
123+
mock_delete.assert_called_once()
124+
125+
@patch("goiam.service_impl.requests.Session.delete")
126+
def test_delete_resource_failure(self, mock_delete):
127+
# Mock failure response
128+
mock_response = Mock()
129+
mock_response.status_code = 404
130+
mock_response.reason = "Not Found"
131+
mock_delete.return_value = mock_response
132+
133+
with self.assertRaises(Exception) as context:
134+
self.service.delete_resource("non-existent", "valid-token")
135+
136+
self.assertIn("Failed to delete resource", str(context.exception))
137+
138+
@patch("goiam.service_impl.requests.Session.delete")
139+
def test_delete_resource_unauthorized(self, mock_delete):
140+
# Mock unauthorized response
141+
mock_response = Mock()
142+
mock_response.status_code = 401
143+
mock_response.reason = "Unauthorized"
144+
mock_delete.return_value = mock_response
145+
146+
with self.assertRaises(Exception) as context:
147+
self.service.delete_resource("resource-id", "invalid-token")
148+
149+
self.assertIn("Failed to delete resource", str(context.exception))
150+
110151

111152
if __name__ == "__main__":
112153
unittest.main()

rust/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)