/
ShopifyApiClient.cs
144 lines (116 loc) · 5.48 KB
/
ShopifyApiClient.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using BTCPayServer.Plugins.Shopify.ApiModels;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace BTCPayServer.Plugins.Shopify
{
public class ShopifyApiClient
{
private readonly HttpClient _httpClient;
private readonly ShopifyApiClientCredentials _credentials;
public ShopifyApiClient(IHttpClientFactory httpClientFactory, ShopifyApiClientCredentials credentials)
{
if (httpClientFactory != null)
{
_httpClient = httpClientFactory.CreateClient(nameof(ShopifyApiClient));
}
else // tests don't provide IHttpClientFactory
{
_httpClient = new HttpClient();
}
_credentials = credentials;
var bearer = $"{_credentials.ApiKey}:{_credentials.ApiPassword}";
bearer = NBitcoin.DataEncoders.Encoders.Base64.EncodeData(Encoding.UTF8.GetBytes(bearer));
_httpClient.DefaultRequestHeaders.Add("Authorization", "Basic " + bearer);
}
private HttpRequestMessage CreateRequest(string shopName, HttpMethod method, string action,
string relativeUrl = null)
{
var url =
$"https://{(shopName.Contains('.', StringComparison.InvariantCulture) ? shopName : $"{shopName}.myshopify.com")}/{relativeUrl ?? ("admin/api/2020-07/" + action)}";
var req = new HttpRequestMessage(method, url);
return req;
}
private async Task<string> SendRequest(HttpRequestMessage req)
{
using var resp = await _httpClient.SendAsync(req);
var strResp = await resp.Content.ReadAsStringAsync();
if (strResp.StartsWith("{", StringComparison.OrdinalIgnoreCase))
{
if (JObject.Parse(strResp)["errors"]?.Value<string>() is string error)
{
if (error == "Not Found")
error = "Shop not found";
throw new ShopifyApiException(error);
}
}
return strResp;
}
public async Task<CreateWebhookResponse> CreateWebhook(string topic, string address, string format = "json")
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Post, $"webhooks.json");
req.Content = new StringContent(JsonConvert.SerializeObject(new { topic, address, format }), Encoding.UTF8,
"application/json");
var strResp = await SendRequest(req);
return JsonConvert.DeserializeObject<CreateWebhookResponse>(strResp);
}
public async Task RemoveWebhook(string id)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Delete, $"webhooks/{id}.json");
var strResp = await SendRequest(req);
}
public async Task<string[]> CheckScopes()
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, null, "admin/oauth/access_scopes.json");
var c = JObject.Parse(await SendRequest(req));
return c["access_scopes"].Values<JToken>()
.Select(token => token["handle"].Value<string>()).ToArray();
}
public async Task<TransactionsListResp> TransactionsList(string orderId)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, $"orders/{orderId}/transactions.json");
var strResp = await SendRequest(req);
var parsed = JsonConvert.DeserializeObject<TransactionsListResp>(strResp);
return parsed;
}
public async Task<TransactionsCreateResp> TransactionCreate(string orderId, TransactionsCreateReq txnCreate)
{
var postJson = JsonConvert.SerializeObject(txnCreate);
var req = CreateRequest(_credentials.ShopName, HttpMethod.Post, $"orders/{orderId}/transactions.json");
req.Content = new StringContent(postJson, Encoding.UTF8, "application/json");
var strResp = await SendRequest(req);
return JsonConvert.DeserializeObject<TransactionsCreateResp>(strResp);
}
public async Task<ShopifyOrder> GetOrder(string orderId)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get,
$"orders/{orderId}.json?fields=id,order_number,total_price,total_outstanding,currency,presentment_currency,transactions,financial_status");
var strResp = await SendRequest(req);
return JObject.Parse(strResp)["order"].ToObject<ShopifyOrder>();
}
public async Task<long> OrdersCount()
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, $"orders/count.json");
var strResp = await SendRequest(req);
var parsed = JsonConvert.DeserializeObject<CountResponse>(strResp);
return parsed.Count;
}
public async Task<bool> OrderExists(string orderId)
{
var req = CreateRequest(_credentials.ShopName, HttpMethod.Get, $"orders/{orderId}.json?fields=id");
var strResp = await SendRequest(req);
return strResp?.Contains(orderId, StringComparison.OrdinalIgnoreCase) == true;
}
}
public class ShopifyApiClientCredentials
{
public string ShopName { get; set; }
public string ApiKey { get; set; }
public string ApiPassword { get; set; }
}
}