Skip to content

Commit

Permalink
🧑‍💻 Introduce fetch util to make it more easy to do requests and to r…
Browse files Browse the repository at this point in the history
…educe code duplication
  • Loading branch information
segersniels committed Apr 5, 2024
1 parent eaa4496 commit d4d17a7
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 19 deletions.
17 changes: 7 additions & 10 deletions apps/cli/src/emoji.zig
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const std = @import("std");
const utils = @import("utils.zig");

const CACHE_FILE = ".genmoji/gitmoji.json";

Expand Down Expand Up @@ -67,9 +68,6 @@ fn writeToCache(allocator: std.mem.Allocator, data: Response) !void {
}

pub fn fetchGitmojis(allocator: std.mem.Allocator) !Response {
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();

// Check if we have a cached version of the gitmojis
if (fetchFromCache(allocator)) |cache| {
// TODO: Figure out a cleaner way to catch the error and only return on actual cache hit
Expand All @@ -80,16 +78,15 @@ pub fn fetchGitmojis(allocator: std.mem.Allocator) !Response {
std.log.debug("Warning: Ignoring error while fetching from cache: {}\n", .{err});
}

const headers = std.http.Client.Request.Headers{ .content_type = std.http.Client.Request.Headers.Value{ .override = "application/json" } };
var body = std.ArrayList(u8).init(allocator);
_ = try client.fetch(.{ .location = .{ .url = "https://gitmoji.dev/api/gitmojis" }, .method = .GET, .headers = headers, .response_storage = .{ .dynamic = &body } });

const data = try std.json.parseFromSlice(Response, allocator, body.items, .{ .allocate = .alloc_always, .ignore_unknown_fields = true });
const response = try utils.fetch(Response, "https://gitmoji.dev/api/gitmojis", .{
.allocator = allocator,
.method = .GET,
});

// Update cache
writeToCache(allocator, data.value) catch |err| {
writeToCache(allocator, response) catch |err| {
std.log.debug("Warning: Ignoring error while writing to cache: {}\n", .{err});
};

return data.value;
return response;
}
18 changes: 9 additions & 9 deletions apps/cli/src/openai.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const std = @import("std");
const emoji = @import("emoji.zig");
const utils = @import("utils.zig");

const Message = struct {
role: []const u8,
Expand Down Expand Up @@ -55,9 +56,6 @@ pub fn getCompletion(allocator: std.mem.Allocator, prompt: []const u8, model: []
std.process.exit(1);
};

var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();

const bearer_token = try std.fmt.allocPrint(allocator, "Bearer {s}", .{api_key});
const headers = std.http.Client.Request.Headers{ .authorization = std.http.Client.Request.Headers.Value{ .override = bearer_token }, .content_type = std.http.Client.Request.Headers.Value{ .override = "application/json" } };

Expand All @@ -74,11 +72,13 @@ pub fn getCompletion(allocator: std.mem.Allocator, prompt: []const u8, model: []
};
defer messages.deinit();

const payload = try std.json.stringifyAlloc(allocator, request, .{});
var body = std.ArrayList(u8).init(allocator);
_ = try client.fetch(.{ .location = .{ .url = "https://api.openai.com/v1/chat/completions" }, .method = .POST, .headers = headers, .response_storage = .{ .dynamic = &body }, .payload = payload });

const data = try std.json.parseFromSlice(CompletionResponse, allocator, body.items, .{ .allocate = .alloc_always, .ignore_unknown_fields = true });
const body = try std.json.stringifyAlloc(allocator, request, .{});
const response = try utils.fetch(CompletionResponse, "https://api.openai.com/v1/chat/completions", .{
.allocator = allocator,
.method = .POST,
.body = body,
.headers = headers,
});

return data.value;
return response;
}
22 changes: 22 additions & 0 deletions apps/cli/src/utils.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const std = @import("std");

const InitOptions = struct {
allocator: std.mem.Allocator,
method: std.http.Method,
body: ?[]u8 = null,
headers: ?std.http.Client.Request.Headers = null,
};

/// Very loosely based on the `fetch` API from JavaScript to make it slightly more user friendly to perform requests
pub fn fetch(comptime T: type, url: []const u8, options: InitOptions) !T {
var client: std.http.Client = .{ .allocator = options.allocator };
defer client.deinit();

const headers = options.headers orelse std.http.Client.Request.Headers{ .content_type = std.http.Client.Request.Headers.Value{ .override = "application/json" } };
var body = std.ArrayList(u8).init(options.allocator);
_ = try client.fetch(.{ .location = .{ .url = url }, .method = options.method, .headers = headers, .response_storage = .{ .dynamic = &body }, .payload = options.body });

const data = try std.json.parseFromSlice(T, options.allocator, body.items, .{ .allocate = .alloc_always, .ignore_unknown_fields = true });

return data.value;
}

0 comments on commit d4d17a7

Please sign in to comment.