Skip to content

Commit 46d0eb8

Browse files
authored
[Feature] Add Profiles Service (#216)
1 parent 0f042d9 commit 46d0eb8

File tree

10 files changed

+254
-0
lines changed

10 files changed

+254
-0
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace CoinbasePro.Specs.JsonFixtures.Services.Profiles
2+
{
3+
public static class AllProfilesResponseFixture
4+
{
5+
public static string Create()
6+
{
7+
var json = @"
8+
[
9+
{
10+
""id"": ""86602c68-306a-4500-ac73-4ce56a91d83c"",
11+
""user_id"": ""5844eceecf7e803e259d0365"",
12+
""name"": ""default"",
13+
""active"": true,
14+
""is_default"": true,
15+
""created_at"": ""2016-12-08T24:00:00Z""
16+
}
17+
]";
18+
19+
return json;
20+
}
21+
}
22+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace CoinbasePro.Specs.JsonFixtures.Services.Profiles
2+
{
3+
public class ProfileResponseFixture
4+
{
5+
public static string Create()
6+
{
7+
var json = @"
8+
{
9+
""id"": ""86602c68-306a-4500-ac73-4ce56a91d83c"",
10+
""user_id"": ""5844eceecf7e803e259d0365"",
11+
""name"": ""default"",
12+
""active"": true,
13+
""is_default"": true,
14+
""created_at"": ""2016-12-08T24:00:00Z""
15+
}";
16+
17+
return json;
18+
}
19+
}
20+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
using CoinbasePro.Network.HttpClient;
2+
using CoinbasePro.Services.Profiles;
3+
using CoinbasePro.Services.Profiles.Models;
4+
using CoinbasePro.Specs.JsonFixtures.Services.Profiles;
5+
using Machine.Fakes;
6+
using Machine.Specifications;
7+
using System.Collections.Generic;
8+
using System.Linq;
9+
using System.Net.Http;
10+
using System.Threading.Tasks;
11+
using System;
12+
using CoinbasePro.Shared.Types;
13+
14+
namespace CoinbasePro.Specs.Services.Profiles
15+
{
16+
[Subject("ProductsService")]
17+
public class ProfilesServiceSpecs : WithSubject<ProfilesService>
18+
{
19+
Establish context = () =>
20+
The<IHttpClient>().WhenToldTo(p => p.SendAsync(Param.IsAny<HttpRequestMessage>()))
21+
.Return(Task.FromResult(new HttpResponseMessage()));
22+
23+
class when_getting_all_profiles
24+
{
25+
static IEnumerable<Profile> result;
26+
27+
Establish context = () =>
28+
The<IHttpClient>().WhenToldTo(p => p.ReadAsStringAsync(Param.IsAny<HttpResponseMessage>()))
29+
.Return(Task.FromResult(AllProfilesResponseFixture.Create()));
30+
31+
Because of = () =>
32+
result = Subject.GetAllProfilesAsync().Result;
33+
34+
It should_have_correct_profiles_response_count = () =>
35+
result.Count().ShouldEqual(1);
36+
37+
It should_have_correct_profiles = () =>
38+
{
39+
result.First().Id.ShouldEqual(new Guid("86602c68-306a-4500-ac73-4ce56a91d83c"));
40+
result.First().UserId.ShouldEqual("5844eceecf7e803e259d0365");
41+
result.First().Name.ShouldEqual("default");
42+
result.First().Active.ShouldEqual(true);
43+
result.First().IsDefault.ShouldEqual(true);
44+
result.First().CreatedAt.ShouldEqual(new DateTime(2016, 12, 9));
45+
};
46+
}
47+
48+
class when_getting_a_profile_by_id
49+
{
50+
static Profile result;
51+
52+
Establish context = () =>
53+
The<IHttpClient>().WhenToldTo(p => p.ReadAsStringAsync(Param.IsAny<HttpResponseMessage>()))
54+
.Return(Task.FromResult(ProfileResponseFixture.Create()));
55+
56+
Because of = () =>
57+
result = Subject.GetProfileByIdAsync(new Guid("86602c68-306a-4500-ac73-4ce56a91d83c")).Result;
58+
59+
It should_have_correct_profile = () =>
60+
{
61+
result.Id.ShouldEqual(new Guid("86602c68-306a-4500-ac73-4ce56a91d83c"));
62+
result.UserId.ShouldEqual("5844eceecf7e803e259d0365");
63+
result.Name.ShouldEqual("default");
64+
result.Active.ShouldEqual(true);
65+
result.IsDefault.ShouldEqual(true);
66+
result.CreatedAt.ShouldEqual(new DateTime(2016, 12, 9));
67+
};
68+
}
69+
70+
class when_creating_a_profile_transfer_on_success
71+
{
72+
static string result;
73+
74+
Establish context = () =>
75+
The<IHttpClient>().WhenToldTo(p => p.ReadAsStringAsync(Param.IsAny<HttpResponseMessage>()))
76+
.Return(Task.FromResult("OK"));
77+
78+
Because of = () =>
79+
result = Subject.CreateProfileTransferAsync(
80+
new Guid("53f58772-76e7-40d7-86bc-8155b80d7b20"),
81+
new Guid("53f58772-76e7-40d7-86bc-8155b80d7b20"),
82+
Currency.BTC,
83+
100).Result;
84+
85+
It should_have_returned_an_ok_response = () =>
86+
result.ShouldEqual("OK");
87+
}
88+
}
89+
}
90+

CoinbasePro/CoinbaseProClient.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using CoinbasePro.Services.Orders;
1313
using CoinbasePro.Services.Payments;
1414
using CoinbasePro.Services.Products;
15+
using CoinbasePro.Services.Profiles;
1516
using CoinbasePro.Services.Reports;
1617
using CoinbasePro.Services.StablecoinConversions;
1718
using CoinbasePro.Services.UserAccount;
@@ -62,6 +63,7 @@ public CoinbaseProClient(
6263
UserAccountService = new UserAccountService(httpClient, httpRequestMessageService);
6364
StablecoinConversionsService = new StablecoinConversionsService(httpClient, httpRequestMessageService);
6465
FeesService = new FeesService(httpClient, httpRequestMessageService);
66+
ProfilesService = new ProfilesService(httpClient, httpRequestMessageService);
6567
WebSocket = new WebSocket.WebSocket(createWebSocketFeed, authenticator, clock);
6668

6769
Log.Information("CoinbaseProClient constructed");
@@ -95,6 +97,8 @@ public CoinbaseProClient(
9597

9698
public IStablecoinConversionsService StablecoinConversionsService { get; }
9799

100+
public IProfilesService ProfilesService { get; }
101+
98102
public IWebSocket WebSocket { get; }
99103
}
100104
}

CoinbasePro/Services/AbstractService.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ protected async Task<T> SendServiceCall<T>(
143143
var httpResponseMessage = await SendHttpRequestMessageAsync(httpMethod, uri, content);
144144
var contentBody = await httpClient.ReadAsStringAsync(httpResponseMessage).ConfigureAwait(false);
145145

146+
if (typeof(T) == typeof(string))
147+
{
148+
return (T)(object)contentBody;
149+
}
150+
146151
return JsonConfig.DeserializeObject<T>(contentBody);
147152
}
148153
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using CoinbasePro.Services.Profiles.Models;
2+
using CoinbasePro.Shared.Types;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Threading.Tasks;
6+
7+
namespace CoinbasePro.Services.Profiles
8+
{
9+
public interface IProfilesService
10+
{
11+
Task<IEnumerable<Profile>> GetAllProfilesAsync();
12+
13+
Task<Profile> GetProfileByIdAsync(Guid id);
14+
15+
Task<string> CreateProfileTransferAsync(
16+
Guid from,
17+
Guid to,
18+
Currency currency,
19+
decimal amount);
20+
}
21+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace CoinbasePro.Services.Profiles.Models
4+
{
5+
public class Profile
6+
{
7+
public Guid Id { get; set; }
8+
9+
public string UserId { get; set; }
10+
11+
public string Name { get; set; }
12+
13+
public bool Active { get; set; }
14+
15+
public bool IsDefault { get; set; }
16+
17+
public DateTime CreatedAt { get; set; }
18+
}
19+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using CoinbasePro.Shared;
2+
using CoinbasePro.Shared.Types;
3+
using Newtonsoft.Json;
4+
using System;
5+
6+
namespace CoinbasePro.Services.Profiles.Models
7+
{
8+
public class ProfileTransfer
9+
{
10+
public Guid From { get; set; }
11+
12+
public Guid To { get; set; }
13+
14+
[JsonConverter(typeof(StringEnumWithDefaultConverter))]
15+
public Currency Currency { get; set; }
16+
17+
public decimal Amount { get; set; }
18+
}
19+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using CoinbasePro.Network.HttpClient;
2+
using CoinbasePro.Network.HttpRequest;
3+
using CoinbasePro.Services.Profiles.Models;
4+
using CoinbasePro.Shared.Types;
5+
using CoinbasePro.Shared.Utilities;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Net.Http;
9+
using System.Threading.Tasks;
10+
11+
namespace CoinbasePro.Services.Profiles
12+
{
13+
public class ProfilesService : AbstractService, IProfilesService
14+
{
15+
public ProfilesService(
16+
IHttpClient httpClient,
17+
IHttpRequestMessageService httpRequestMessageService)
18+
: base(httpClient, httpRequestMessageService)
19+
{
20+
}
21+
22+
public async Task<IEnumerable<Profile>> GetAllProfilesAsync()
23+
{
24+
return await SendServiceCall<List<Profile>>(HttpMethod.Get, "/profiles");
25+
}
26+
27+
public async Task<Profile> GetProfileByIdAsync(Guid id)
28+
{
29+
return await SendServiceCall<Profile>(HttpMethod.Get, $"/profiles/{id}");
30+
}
31+
32+
public async Task<string> CreateProfileTransferAsync(
33+
Guid from,
34+
Guid to,
35+
Currency currency,
36+
decimal amount)
37+
{
38+
var newProfileTransfer = new ProfileTransfer
39+
{
40+
From = from,
41+
To = to,
42+
Currency = currency,
43+
Amount = amount
44+
};
45+
46+
return await SendServiceCall<string>(HttpMethod.Post, "/profiles/transfer", JsonConfig.SerializeObject(newProfileTransfer)).ConfigureAwait(false);
47+
}
48+
}
49+
}

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ var allAccounts = await coinbaseProClient.AccountsService.GetAllAccountsAsync();
9292
###### Stablecoin Conversions ######
9393
- CreateConversion(currencyFrom, currencyTo, amount) - convert bank-based dollars to blockchain-based digital dollars
9494

95+
###### Profiles ######
96+
- GetAllProfilesAsync() - list your profiles
97+
- GetProfileByIdAsync(id) - get a single profile by profile id
98+
- CreateProfileTransferAsync(from, to, currency, amount) - transfer funds from API key’s profile to another user owned profile
99+
95100
<h1>Websocket Feed</h1>
96101
<h2>How to use with authentication</h2>
97102

0 commit comments

Comments
 (0)