Skip to content

Commit

Permalink
Working version
Browse files Browse the repository at this point in the history
  • Loading branch information
Binali Rustamov committed Dec 22, 2019
1 parent 70f94b7 commit 2a5c8cb
Show file tree
Hide file tree
Showing 28 changed files with 485 additions and 88 deletions.
45 changes: 43 additions & 2 deletions PortainerClient/Api/Base/BaseApiHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,55 @@
using System;
using System.Collections.Generic;
using RestSharp;

namespace PortainerClient.Api
namespace PortainerClient.Api.Base
{
/// <summary>
/// Helpers for the Portainer API
/// </summary>
public static class BaseApiHelpers
{
public static void AddParameters(this RestRequest request,
/// <summary>
/// Fill the request with provided parameters
/// </summary>
/// <param name="request">API request</param>
/// <param name="parameters">List with request parameters</param>
public static void AddParameters(this IRestRequest request,
IEnumerable<(string paramName, object paramValue)> parameters)
{
foreach (var (paramName, paramValue) in parameters) request.AddParameter(paramName, paramValue);
}

/// <summary>
/// Fill the request with provided parameters
/// </summary>
/// <param name="request">API request</param>
/// <param name="parameters">List with request parameters</param>
/// <exception cref="InvalidOperationException">Occurs when parameter type is not implemented</exception>
public static void AddParameters(this IRestRequest request,
IEnumerable<(string paramName, object value, ParamType type)> parameters)
{
foreach (var (paramName, value, type) in parameters)
{
switch (type)
{
case ParamType.File:
request.AddFile(paramName, value.ToString());
break;
case ParamType.QueryParam:
request.AddQueryParameter(paramName, value.ToString());
break;
case ParamType.BodyParam:
request.AddParameter(paramName, value);
break;
case ParamType.JsonBody:
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(value);
break;
default:
throw new InvalidOperationException($"You should define parameter type for {paramName} ");
}
}
}
}
}
87 changes: 69 additions & 18 deletions PortainerClient/Api/Base/BaseApiService.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System;
using PortainerClient.Api.Model;
using PortainerClient.Helpers;
using PortainerClient.Config;
using RestSharp;
using RestSharp.Authenticators;

namespace PortainerClient.Api
namespace PortainerClient.Api.Base
{
/// <summary>
/// Base implementation of Portainer API service
/// </summary>
public abstract class BaseApiService
{
private RestClient _client;
Expand All @@ -20,31 +23,79 @@ private RestClient ResolveClient()
return _client;
}

protected T Get<T>(string resource, params (string paramName, object paramValue)[] parameters) where T : new()
{
var request = new RestRequest(resource, Method.GET);
request.AddParameters(parameters);
var response = ResolveClient().Execute<T>(request);
if (response.IsSuccessful) return response.Data;
throw ParseError(resource, response.Content);
}
/// <summary>
/// Do Get request and return parsed response
/// </summary>
/// <param name="resource">API resource</param>
/// <param name="parameters">List of request parameters</param>
/// <typeparam name="T">Response type</typeparam>
/// <returns>Parsed instance of T</returns>
protected T Get<T>(string resource, params (string paramName, object paramValue)[] parameters)
where T : new() =>
ExecuteRequest<T>(
resource,
Method.GET,
request => request.AddParameters(parameters));

/// <summary>
/// Do Post request and return parsed response
/// </summary>
/// <param name="resource">API resource</param>
/// <param name="parameters">List of request parameters</param>
/// <typeparam name="T">Parsed instance of T</typeparam>
/// <returns>Parsed instance of T</returns>
protected T Post<T>(string resource, params (string paramName, object value, ParamType type)[] parameters)
where T : new() => ExecuteRequest<T>(
resource,
Method.POST,
request => request.AddParameters(parameters));

/// <summary>
/// Do Put request and return parsed response
/// </summary>
/// <param name="resource">API resource</param>
/// <param name="parameters">List of request parameters</param>
/// <typeparam name="T">Parsed instance of T</typeparam>
/// <returns>Parsed instance of T</returns>
protected T Put<T>(string resource,
params (string paramName, object value, ParamType type)[] parameters)
where T : new() => ExecuteRequest<T>(
resource,
Method.PUT,
request => request.AddParameters(parameters));

protected void Delete(string resource, params (string paramName, object paramValue)[] parameters)
/// <summary>
/// Do Delete request and return parsed response
/// </summary>
/// <param name="resource">API resource</param>
/// <param name="parameters">List of request parameters</param>
protected void Delete(string resource, params (string paramName, object paramValue)[] parameters) =>
ExecuteRequest(resource, Method.DELETE, request => request.AddParameters(parameters));

private void ExecuteRequest(string resource, Method method, Action<IRestRequest> requestConfig = null)
{
var request = new RestRequest(resource, Method.DELETE);
request.AddParameters(parameters);
var request = new RestRequest(resource, method);
requestConfig?.Invoke(request);
var response = ResolveClient().Execute(request);
if (response.IsSuccessful) return;
throw ParseError(resource, response.Content);
throw ParseError(request.Resource, response.Content);
}

private T ExecuteRequest<T>(string resource, Method method, Action<IRestRequest> requestConfig = null)
where T : new()
{
var request = new RestRequest(resource, method);
requestConfig?.Invoke(request);
var response = ResolveClient().Execute<T>(request);
if (response.IsSuccessful)
return response.Data;
throw ParseError(request.Resource, response.Content);
}

private static InvalidOperationException ParseError(string resource, string responseData)
{
ApiError errorInfo = null;
if (responseData != null)
{
errorInfo = SimpleJson.DeserializeObject<ApiError>(responseData);
}
if (responseData != null) errorInfo = SimpleJson.DeserializeObject<ApiError>(responseData);

return new InvalidOperationException(
$"Request {resource}: {(errorInfo != null ? $"{errorInfo.message}, details: {errorInfo.details}" : "no information")}");
Expand Down
28 changes: 28 additions & 0 deletions PortainerClient/Api/Base/ParamType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace PortainerClient.Api.Base
{
/// <summary>
/// Request parameter types
/// </summary>
public enum ParamType
{
/// <summary>
/// File parameter (send file to server)
/// </summary>
File,

/// <summary>
/// Query parameter (attach parameter to query string)
/// </summary>
QueryParam,

/// <summary>
/// Body parameter (attach parameter to body (form))
/// </summary>
BodyParam,

/// <summary>
/// JSON Body parameter (attach parameter as JSON Body of request)
/// </summary>
JsonBody
}
}
9 changes: 9 additions & 0 deletions PortainerClient/Api/Model/ApiError.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// General model for Portainer API error
/// </summary>
public class ApiError
{
/// <summary>
/// Message about occured error
/// </summary>
public string message { get; set; }
/// <summary>
/// Occured error details
/// </summary>
public string details { get; set; }
}
}
11 changes: 10 additions & 1 deletion PortainerClient/Api/Model/AuthInfo.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// Model for authorization process
/// </summary>
public class AuthInfo
{
/// <summary>
/// User's login
/// </summary>
public string Username { get; set; }
/// <summary>
/// User's password
/// </summary>
public string Password { get; set; }
}
}
}
11 changes: 10 additions & 1 deletion PortainerClient/Api/Model/StackEnv.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// Model for stack's environment variable
/// </summary>
public class StackEnv
{
/// <summary>
/// Environment variable name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Environment variable value
/// </summary>
public string Value { get; set; }
}
}
}
6 changes: 6 additions & 0 deletions PortainerClient/Api/Model/StackFileInspect.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// Stack file inspect model
/// </summary>
public class StackFileInspect
{
/// <summary>
/// Stack file content (as string)
/// </summary>
public string StackFileContent { get; set; }
}
}
29 changes: 28 additions & 1 deletion PortainerClient/Api/Model/StackInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,42 @@

namespace PortainerClient.Api.Model
{
/// <summary>
/// Stack instance information
/// </summary>
public class StackInfo
{
/// <summary>
/// Stack id in portainer
/// </summary>
public string Id { get; set; }
/// <summary>
/// Stack name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Type of stack
/// </summary>
public StackType Type { get; set; }
/// <summary>
/// Endpoint identifier in Portainer where the stack is deployed
/// </summary>
public int EndpointId { get; set; }
/// <summary>
/// Stack file location
/// </summary>
public string EntryPoint { get; set; }
/// <summary>
/// Swarm identifier in Portainer where the stack is deployed
/// </summary>
public string SwarmId { get; set; }
/// <summary>
/// Path on disk to the repository that hosts the stack file
/// </summary>
public string ProjectPath { get; set; }
/// <summary>
/// List of environment variables for the stack
/// </summary>
public IEnumerable<StackEnv> Env { get; set; }
}
}
}
11 changes: 10 additions & 1 deletion PortainerClient/Api/Model/StackType.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// Stack types
/// </summary>
public enum StackType
{
/// <summary>
/// Swarm stack
/// </summary>
Swarm = 1,
/// <summary>
/// Docker compose stack
/// </summary>
Compose = 2
}
}
}
8 changes: 7 additions & 1 deletion PortainerClient/Api/Model/TokenInfo.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
namespace PortainerClient.Api.Model
{
/// <summary>
/// Token information model
/// </summary>
public class TokenInfo
{
/// <summary>
/// JWT Token for authorized user
/// </summary>
public string Jwt { get; set; }
}
}
}
Loading

0 comments on commit 2a5c8cb

Please sign in to comment.