C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
http_client_abstract.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include "../abi/json.hpp"
26#include "../error_extensions.hpp"
27#include "../exception.hpp"
28#include "../meta/identifier.hpp"
29#include "../range.hpp"
30#include "common_types.hpp"
31#include "http_headers_proxy.hpp"
32#include "rest_api.hpp"
33#include "uri.hpp"
34
35#include <concepts>
36#include <exception>
37#include <span>
38#include <string_view>
39#include <tuple>
40#include <type_traits>
41#include <utility>
42
43namespace essence::net {
44 template <typename Impl>
46 public:
47 friend Impl;
48
49 [[nodiscard]] const uri& base_uri() const {
50 return self().base_uri();
51 }
52
53 [[nodiscard]] abi::json commit_json_nop(
54 http_method method, const uri& relative_uri, const http_header_handler& header_handler = {}) const {
55 return self().commit_json_nop(method, relative_uri, header_handler);
56 }
57
58 [[nodiscard]] abi::json commit_json(http_method method, const uri& relative_uri, const abi::json& params,
59 const http_header_handler& header_handler = {}) const {
60 return self().commit_json(method, relative_uri, params, header_handler);
61 }
62
63 [[nodiscard]] abi::json commit_bytes(http_method method, const uri& relative_uri, std::string_view content_type,
64 std::span<const std::byte> bytes, const http_header_handler& header_handler = {}) const {
65 return self().commit_bytes(method, relative_uri, content_type, bytes, header_handler);
66 }
67
68 template <byte_like_contiguous_range Range>
69 abi::json commit_bytes(http_method method, const uri& relative_uri, std::string_view content_type,
70 Range&& bytes, const http_header_handler& header_handler = {}) const {
71 return self().commit_bytes(method, relative_uri, content_type, as_const_byte_span(bytes), header_handler);
72 }
73
74 void on_progress(const http_progress_handler& progress_handler) const {
75 return self().on_progress(progress_handler);
76 }
77
78 template <typename T>
80 auto commit_message(T&& message, const http_header_handler& header_handler = {}) const {
81 using decayed_type = std::decay_t<T>;
82 using traits_type = rest_message_traits<decayed_type>;
83
84 static constexpr bool is_dummy_message = std::derived_from<decayed_type, dummy_body_tag>;
85
86 auto handler = [header_handler, this]<typename U>(U&& message) {
87 static_assert(
89 "An invalid \"message_transformer\" found.");
90
91 auto params = [&] {
92 if constexpr (is_dummy_message) {
93 return abi::json{};
94 } else if constexpr (has_rest_message_transformer<decayed_type>) {
95 return abi::to_abi_json(rest_message_transformer_v<decayed_type>(std::forward<U>(message)));
96 } else {
97 return abi::to_abi_json(json(std::forward<U>(message)));
98 }
99 }();
100
101 auto response = [&] {
102 auto raw_response = [&] {
103 if constexpr (is_dummy_message) {
104 return abi::from_abi_json(
105 commit_json_nop(traits_type::method, traits_type::relative_uri, header_handler));
106 } else {
107 return abi::from_abi_json(
108 commit_json(traits_type::method, traits_type::relative_uri, params, header_handler));
109 }
110 }();
111
112 try {
113 return raw_response.template get<typename traits_type::response_type>();
114 } catch (...) {
115 std::throw_with_nested(source_code_aware_runtime_error{
116 U8("Raw Response"), raw_response.dump(default_nested_exception_indent)});
117 }
118 }();
119
122 "An invalid \"response_transformer\" found.");
123
125 return rest_response_transformer_v<decayed_type>(response);
126 } else {
127 return response;
128 }
129 };
130
131 auto message_content = [&] {
132 if constexpr (is_dummy_message) {
133 return U8("");
134 } else {
135 return json(message).dump(default_nested_exception_indent);
136 }
137 }();
138
139 auto tuple = std::forward_as_tuple(std::forward<T>(message));
140
141 return throw_nested_and_flatten(
142 source_code_aware_runtime_error{U8("Error"), U8("Failed to commit the message."), U8("Entity"),
143 meta::get_literal_string_t<decayed_type,
145 .shortened = true,
146 }>(),
147 U8("Raw Message"), message_content},
148 [&] { return std::apply(handler, std::move(tuple)); });
149 }
150
151 private:
152 http_client_abstract() = default;
153
154 Impl& self() noexcept {
155 return static_cast<Impl&>(*this);
156 }
157
158 const Impl& self() const noexcept {
159 return static_cast<const Impl&>(*this);
160 }
161 };
162} // namespace essence::net
Definition http_client_abstract.hpp:45
Definition uri.hpp:37
Definition rest_api.hpp:45
Definition identifier_param.hpp:26
Definition rest_api.hpp:42
An exception class derived from std::runtime_error that provides source code information of the sourc...
Definition error_extensions.hpp:73