Skip to content

Commit ff34818

Browse files
committed
Improve builder
1 parent c126722 commit ff34818

File tree

4 files changed

+130
-105
lines changed

4 files changed

+130
-105
lines changed

README.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ forge install Recon-Fuzz/solidity-http
1313
### 1. Import the library
1414

1515
```solidity
16-
import {HTTP} from "solidity-http/HTTP.sol";
17-
import {HTTPBuilder} from "solidity-http/HTTPBuilder.sol";
16+
import {HTTP} from "@src/HTTP.sol";
1817
```
1918

2019
### 2. Build and send your request
@@ -23,18 +22,17 @@ Use builder functions to compose your request with headers, body, and query para
2322

2423
```solidity
2524
contract MyScript is Script {
26-
using HTTPBuilder for HTTP.Request;
25+
using HTTP for HTTP.Builder;
26+
using HTTP for HTTP.Request;
2727
28-
HTTP.Request request;
28+
HTTP.Builder http;
2929
3030
function run() external {
31-
request
32-
.withUrl("https://httpbin.org/post")
33-
.withMethod(HTTP.Method.POST)
31+
HTTP.Response memory response = http.build().POST("https://httpbin.org/post")
3432
.withHeader("Content-Type", "application/json")
35-
.withBody('{"foo": "bar"}');
36-
37-
HTTP.Response memory response = HTTP.request(request);
33+
.withHeader("Accept", "application/json")
34+
.withBody('{"foo": "bar"}')
35+
.request();
3836
3937
console.log("Status:", response.status);
4038
console.log("Data:", response.data);

src/HTTP.sol

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ library HTTP {
99

1010
Vm constant vm = Vm(address(bytes20(uint160(uint256(keccak256("hevm cheat code"))))));
1111

12+
error HTTPBuilderInvalidArrayLengths(uint256 a, uint256 b);
13+
1214
enum Method {
1315
GET,
1416
POST,
@@ -30,6 +32,112 @@ library HTTP {
3032
string data;
3133
}
3234

35+
struct Builder {
36+
Request[] requests;
37+
}
38+
39+
function build(HTTP.Builder storage builder) internal returns (HTTP.Request storage) {
40+
builder.requests.push();
41+
return builder.requests[builder.requests.length - 1];
42+
}
43+
44+
function withUrl(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
45+
req.url = url;
46+
return req;
47+
}
48+
49+
function withMethod(HTTP.Request storage req, HTTP.Method method) internal returns (HTTP.Request storage) {
50+
req.method = method;
51+
return req;
52+
}
53+
54+
function GET(HTTP.Request storage req) internal returns (HTTP.Request storage) {
55+
return withMethod(req, HTTP.Method.GET);
56+
}
57+
58+
function GET(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
59+
return withUrl(withMethod(req, HTTP.Method.GET), url);
60+
}
61+
62+
function POST(HTTP.Request storage req) internal returns (HTTP.Request storage) {
63+
return withMethod(req, HTTP.Method.POST);
64+
}
65+
66+
function POST(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
67+
return withUrl(withMethod(req, HTTP.Method.POST), url);
68+
}
69+
70+
function PUT(HTTP.Request storage req) internal returns (HTTP.Request storage) {
71+
return withMethod(req, HTTP.Method.PUT);
72+
}
73+
74+
function PUT(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
75+
return withUrl(withMethod(req, HTTP.Method.PUT), url);
76+
}
77+
78+
function DELETE(HTTP.Request storage req) internal returns (HTTP.Request storage) {
79+
return withMethod(req, HTTP.Method.DELETE);
80+
}
81+
82+
function DELETE(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
83+
return withUrl(withMethod(req, HTTP.Method.DELETE), url);
84+
}
85+
86+
function PATCH(HTTP.Request storage req) internal returns (HTTP.Request storage) {
87+
return withMethod(req, HTTP.Method.PATCH);
88+
}
89+
90+
function PATCH(HTTP.Request storage req, string memory url) internal returns (HTTP.Request storage) {
91+
return withUrl(withMethod(req, HTTP.Method.PATCH), url);
92+
}
93+
94+
function withBody(HTTP.Request storage req, string memory body) internal returns (HTTP.Request storage) {
95+
req.body = body;
96+
return req;
97+
}
98+
99+
function withHeader(HTTP.Request storage req, string memory key, string memory value)
100+
internal
101+
returns (HTTP.Request storage)
102+
{
103+
req.headers.set(key, value);
104+
return req;
105+
}
106+
107+
function withHeader(HTTP.Request storage req, string[] memory keys, string[] memory values)
108+
internal
109+
returns (HTTP.Request storage)
110+
{
111+
if (keys.length != values.length) {
112+
revert HTTPBuilderInvalidArrayLengths(keys.length, values.length);
113+
}
114+
for (uint256 i = 0; i < keys.length; i++) {
115+
req.headers.set(keys[i], values[i]);
116+
}
117+
return req;
118+
}
119+
120+
function withQuery(HTTP.Request storage req, string memory key, string memory value)
121+
internal
122+
returns (HTTP.Request storage)
123+
{
124+
req.query.set(key, value);
125+
return req;
126+
}
127+
128+
function withQuery(HTTP.Request storage req, string[] memory keys, string[] memory values)
129+
internal
130+
returns (HTTP.Request storage)
131+
{
132+
if (keys.length != values.length) {
133+
revert HTTPBuilderInvalidArrayLengths(keys.length, values.length);
134+
}
135+
for (uint256 i = 0; i < keys.length; i++) {
136+
req.query.set(keys[i], values[i]);
137+
}
138+
return req;
139+
}
140+
33141
function request(Request storage req) internal returns (Response memory res) {
34142
string memory scriptStart = 'response=$(curl -s -w "\\n%{http_code}" ';
35143
string memory scriptEnd =

src/HTTPBuilder.sol

Lines changed: 0 additions & 68 deletions
This file was deleted.

test/HTTP.t.sol

Lines changed: 14 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,28 @@ pragma solidity ^0.8.13;
44
import "forge-std/Test.sol";
55

66
import {HTTP} from "@src/HTTP.sol";
7-
import {HTTPBuilder} from "@src/HTTPBuilder.sol";
8-
import {strings} from "solidity-stringutils/strings.sol";
9-
import {StringMap} from "@src/StringMap.sol";
107
import {strings} from "solidity-stringutils/strings.sol";
118
import {stdJson} from "forge-std/StdJson.sol";
129

1310
contract HTTPTest is Test {
11+
using HTTP for HTTP.Builder;
1412
using HTTP for HTTP.Request;
15-
using HTTPBuilder for HTTP.Request;
16-
using StringMap for StringMap.StringToStringMap;
1713
using strings for *;
1814
using stdJson for string;
1915

20-
HTTP.Request req;
21-
StringMap.StringToStringMap headers;
22-
StringMap.StringToStringMap query;
16+
HTTP.Builder http;
2317

2418
function test_HTTP_GET() public {
25-
req.withUrl("https://jsonplaceholder.typicode.com/todos/1").withMethod(HTTP.Method.GET);
26-
HTTP.Response memory res = req.request();
19+
HTTP.Response memory res = http.build().GET("https://jsonplaceholder.typicode.com/todos/1").request();
2720

2821
assertEq(res.status, 200);
2922
assertEq(res.data, '{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}');
3023
}
3124

3225
function test_HTTP_GET_options() public {
33-
req.withUrl("https://httpbin.org/headers").withHeader("accept", "application/json").withHeader(
34-
"Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
35-
).withMethod(HTTP.Method.GET);
36-
HTTP.Response memory res = req.request();
26+
HTTP.Response memory res = http.build().GET("https://httpbin.org/headers").withHeader(
27+
"accept", "application/json"
28+
).withHeader("Authorization", "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==").request();
3729

3830
assertEq(res.status, 200);
3931

@@ -42,8 +34,8 @@ contract HTTPTest is Test {
4234
}
4335

4436
function test_HTTP_POST_form_data() public {
45-
req.withUrl("https://httpbin.org/post").withMethod(HTTP.Method.POST).withBody("[email protected]");
46-
HTTP.Response memory res = req.request();
37+
HTTP.Response memory res =
38+
http.build().POST("https://httpbin.org/post").withBody("[email protected]").request();
4739

4840
assertEq(res.status, 200);
4941

@@ -52,40 +44,35 @@ contract HTTPTest is Test {
5244
}
5345

5446
function test_HTTP_POST_json() public {
55-
req.withUrl("https://httpbin.org/post").withMethod(HTTP.Method.POST).withBody('{"foo": "bar"}');
56-
HTTP.Response memory res = req.request();
47+
HTTP.Response memory res = http.build().POST("https://httpbin.org/post").withBody('{"foo": "bar"}').request();
5748

5849
assertEq(res.status, 200);
5950
assertTrue(res.data.toSlice().contains(("foo").toSlice()));
6051
assertTrue(res.data.toSlice().contains(("bar").toSlice()));
6152
}
6253

6354
function test_HTTP_PUT() public {
64-
req.withUrl("https://httpbin.org/put").withMethod(HTTP.Method.PUT);
65-
HTTP.Response memory res = req.request();
55+
HTTP.Response memory res = http.build().PUT("https://httpbin.org/put").request();
6656
assertEq(res.status, 200);
6757
}
6858

6959
function test_HTTP_PUT_json() public {
70-
req.withUrl("https://httpbin.org/put").withMethod(HTTP.Method.PUT).withBody('{"foo": "bar"}').withHeader(
60+
HTTP.Response memory res = http.build().PUT("https://httpbin.org/put").withBody('{"foo": "bar"}').withHeader(
7161
"Content-Type", "application/json"
72-
);
73-
HTTP.Response memory res = req.request();
62+
).request();
7463

7564
assertEq(res.status, 200);
7665
assertTrue(res.data.toSlice().contains(('"foo"').toSlice()));
7766
assertTrue(res.data.toSlice().contains(('"bar"').toSlice()));
7867
}
7968

8069
function test_HTTP_DELETE() public {
81-
req.withUrl("https://httpbin.org/delete").withMethod(HTTP.Method.DELETE);
82-
HTTP.Response memory res = req.request();
70+
HTTP.Response memory res = http.build().DELETE("https://httpbin.org/delete").request();
8371
assertEq(res.status, 200);
8472
}
8573

8674
function test_HTTP_PATCH() public {
87-
req.withUrl("https://httpbin.org/patch").withMethod(HTTP.Method.PATCH);
88-
HTTP.Response memory res = req.request();
75+
HTTP.Response memory res = http.build().PATCH("https://httpbin.org/patch").request();
8976
assertEq(res.status, 200);
9077
}
9178
}

0 commit comments

Comments
 (0)