Nyaraka za API ya MakeFav
Tengeneza vifurushi kamili vya favicon kutoka kwenye msimbo wako, skripti za ujenzi na mifumo ya CI. Ombi moja hubadilisha picha yoyote kuwa favicon.ico, Apple touch icon, aikoni za Android na PWA, web manifest na HTML iliyo tayari kubandikwa.
Kwenye ukurasa huu
Kuanza haraka
API ya MakeFav ni REST API rahisi ya HTTPS + JSON. Endpoint zote ziko chini ya URL moja ya msingi:
https://makefav.com/api/v1 - Fungua akaunti bila malipo
Jisajili, thibitisha anwani yako ya barua pepe na uendelee kuwa mfuasi wa jarida la MakeFav – hiyo ndiyo sharti pekee la mpango wa bure. - Unda API key
Fungua ukurasa wa API keys kwenye akaunti yako na uunde ufunguo wako binafsi. Huanza na mf_ na huonyeshwa mara moja tu, kwa hivyo uuhifadhi kwa usalama. Simamia API keys - Tuma ombi lako la kwanza
Pakia picha kwenye endpoint ya generate kisha uhifadhi faili ya ZIP itakayorejeshwa:
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip Unzip favicons.zip, upload the files to your website and paste the HTML code from the end of readme-makefav.txt into the <head> of every page.
Uthibitishaji
Kila ombi kwa endpoint iliyolindwa lazima lijumuishe API key binafsi. Unaweza kuunda, kutaja majina na kufuta funguo wakati wowote kwenye ukurasa wa akaunti yako: API keys
Send the key as a bearer token in the Authorization header, or – if your HTTP client makes that awkward – in the X-API-Key header. Both are equivalent.
Authorization: Bearer mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or, alternatively
X-API-Key: mf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Missing or invalid keys return 401 Unauthorized. The GET /sizes and GET /openapi.json endpoints do not require a key.
Vikomo vya maombi
Kwa chaguo-msingi kila API key inaweza kutuma maombi 100 kwa saa. Kila jibu lililothibitishwa hukuonyesha ulipofikia:
| Kichwa | Maelezo |
|---|---|
X-RateLimit-Limit | Idadi ya juu zaidi ya maombi yanayoruhusiwa katika kipindi cha sasa. |
X-RateLimit-Remaining | Maombi yaliyosalia katika kipindi cha sasa. |
X-RateLimit-Reset | Unix timestamp (sekunde, UTC) kipindi kinapoanza upya. |
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 97
X-RateLimit-Reset: 1767225600 When the limit is exceeded the API responds with HTTP 429 and the error code rate_limited. Wait until the time in X-RateLimit-Reset before retrying – do not retry in a tight loop.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1767225600
{"error": {"code": "rate_limited", "message": "Rate limit exceeded. Try again after the reset time."}} You can check your current quota at any time with GET /me.
Endpoint
| Endpoint | Uthibitishaji | Maelezo |
|---|---|---|
POST /generate | API key | Unda kifurushi kamili cha favicon. |
GET /me | API key | Akaunti yako na hali ya sasa ya kikomo cha maombi. |
GET /sizes | Hakuna | Orodha ya faili zote za ikoni na ukubwa unaozalishwa na jenereta. |
GET /openapi.json | Hakuna | Maelezo ya OpenAPI 3.1 yanayosomeka na mashine. |
Tengeneza kifurushi cha favicon
/generateHuunda kifurushi kamili cha favicon kutoka picha moja ya chanzo. Tuma picha kwa mojawapo ya njia tatu:
| Aina ya maudhui | Sehemu ya picha | Maelezo |
|---|---|---|
multipart/form-data | image | Kupakia faili. Inapendekezwa – ndiyo njia yenye ufanisi zaidi. |
application/json | image_base64 | Base64-encoded image, either raw base64 or a data URL such as data:image/png;base64,iVBOR…. |
application/json | image_url | URL ya umma ya http au https ya picha. Seva huipakua (kiwango cha juu MB 10). |
Miundo ya ingizo inayotumika: PNG, JPG, WebP, AVIF, GIF, BMP, SVG na ICO. Ukubwa wa juu wa faili: MB 10.
Vigezo
Vigezo vyote ni vya hiari. Vitume kama sehemu za fomu (multipart) au kama sifa za JSON. Thamani zisizo sahihi hutumia chaguo-msingi.
| Jina | Aina / kiwango | Chaguo-msingi | Maelezo |
|---|---|---|---|
app_name | mfuatano wa maandishi, herufi 60 kwa juu | My Website | Jina la tovuti au programu yako, linalotumika katika manifest.json na ukurasa wa mfano. |
short_name | mfuatano wa maandishi, herufi 24 kwa juu | herufi 12 za kwanza za app_name | Jina fupi linaloonyeshwa chini ya ikoni kwenye skrini ya mwanzo ya Android. |
theme_color | #rrggbb | #ffffff | Rangi ya kiolesura cha kivinjari (lebo ya meta ya theme-color na manifest). |
tile_color | #rrggbb | sawa na theme_color | Rangi ya mandharinyuma ya vigae vya Windows Start. |
background | transparent | #rrggbb | transparent | Mandharinyuma ya ikoni za kivinjari, Android na Windows. |
apple_background | #rrggbb | #ffffff | Mandharinyuma ya ikoni za Apple touch na ikoni ya maskable (iOS haitumii uwazi). Hupuuzwa wakati mandharinyuma ni rangi – rangi hiyo hutumika badala yake. |
padding | nambari kamili, 0–40 (%) | 0 | Nafasi tupu kuzunguka picha, kama asilimia ya ukubwa wa ikoni. |
radius | nambari kamili, 0–50 (%) | 0 | Pembe zilizozungushwa. 50 huunda duara. Haitumiki kwa ikoni za Apple, ambazo iOS huzizungusha yenyewe. |
zoom | nambari kamili, 50–400 (%) | 100 | Kipimo cha picha ndani ya ikoni. Thamani zaidi ya 100 hukata picha. |
offset_x, offset_y | nambari, -1 hadi 1 | 0 | Husogeza picha kwa mlalo / wima, kama sehemu ya ukubwa wa ikoni. |
path | mfuatano wa maandishi | / | Folda kwenye seva yako ambako ikoni zitakaa. Hutumika katika msimbo wa HTML, manifest na browserconfig. |
display | standalone | fullscreen | minimal-ui | browser | standalone | Hali ya onyesho la PWA inayoandikwa kwenye manifest. |
pixelated | auto | 1 | 0 | auto | Ukuzaji mkali wa nearest-neighbour kwa pixel art. auto huuwasha kwa vyanzo vya px 64 au chini. |
maskable | 1 | 0 | 1 | Pia tengeneza maskable-icon-512x512.png yenye nafasi salama ya pembeni kwa ikoni zinazojirekebisha za Android. |
ico_sizes | orodha iliyotenganishwa kwa koma ya 16, 24, 32, 48, 64, 128, 256 | 16,32,48 | Ukubwa unaowekwa ndani ya favicon.ico. |
groups | orodha iliyotenganishwa kwa koma ya favicon, apple, android, ms | favicon,apple,android,ms | Seti za ikoni za kutengeneza: favicon za kivinjari, ikoni za Apple touch, ikoni za Android / PWA na vigae vya Windows. |
format | zip | json | zip | Muundo wa jibu – tazama hapa chini. |
Jibu
format=zip- Binary ZIP archive with
Content-Type: application/zipandContent-Disposition: attachment. Default. format=json- JSON object with the package
id(32 hex characters), thehtmlsnippet for your <head> and afilesarray; each file hasname,mime,size(bytes) andbase64contents.
Mfano wa ombi – multipart, jibu la ZIP
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip HTTP/1.1 200 OK
Content-Type: application/zip
Content-Disposition: attachment
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1767225600
<binary ZIP data> Mfano wa ombi – JSON yenye URL ya picha, jibu la JSON
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"image_url": "https://example.com/logo.png",
"app_name": "My App",
"theme_color": "#2f9e68",
"radius": 20,
"groups": "favicon,apple,android",
"format": "json"
}' {
"id": "9f86d081884c7d659a2feaa0c55ad015",
"html": "<link rel=\"apple-touch-icon\" sizes=\"57x57\" href=\"/apple-icon-57x57.png\">\n…\n<meta name=\"theme-color\" content=\"#2f9e68\">",
"files": [
{"name": "favicon.ico", "mime": "image/x-icon", "size": 15086, "base64": "AAABAAMAEBAAAAEAIABoBAAANgAAACAg…"},
{"name": "favicon-16x16.png", "mime": "image/png", "size": 612, "base64": "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ…"},
{"name": "manifest.json", "mime": "application/json", "size": 1094, "base64": "ewogICAgIm5hbWUiOiAiTXkgQXBwIiwK…"}
]
}
Pata akaunti yako
/meHurejesha mtumiaji anayemiliki ufunguo wa API na hali ya sasa ya kikomo cha maombi. Ni muhimu kuthibitisha ufunguo. Inahitaji uthibitishaji; hakuna vigezo.
Mfano wa ombi
curl -sS https://makefav.com/api/v1/me \
-H "Authorization: Bearer $MAKEFAV_API_KEY" Mfano wa jibu
{
"id": 1,
"email": "[email protected]",
"name": "Jane Doe",
"rate_limit": {"limit": 100, "remaining": 97, "reset": 1767225600}
}
Orodhesha ukubwa wa ikoni
/sizesReturns every icon file the generator can produce, with its pixel size and group. No authentication and no parameters. The group value matches the groups parameter of POST /generate.
Mfano wa ombi
curl -sS https://makefav.com/api/v1/sizes Mfano wa jibu
{
"files": [
{"name": "favicon-16x16.png", "size": 16, "group": "favicon"},
{"name": "favicon-32x32.png", "size": 32, "group": "favicon"},
{"name": "apple-touch-icon.png", "size": 180, "group": "apple"},
{"name": "android-icon-192x192.png", "size": 192, "group": "android"},
{"name": "ms-icon-144x144.png", "size": 144, "group": "ms"}
]
}
Maelezo ya OpenAPI
/openapi.jsonHurejesha maelezo ya OpenAPI 3.1 ya API hii. Hakuna uthibitishaji. Yaingize kwenye Postman, Insomnia au Swagger UI, au yatumie kutengeneza mteja mwenye aina kwa lugha yako.
curl -sS https://makefav.com/api/v1/openapi.json -o makefav-openapi.json Hitilafu
Successful requests return HTTP 200. Every error returns a JSON body with a stable, machine-readable code and a human-readable message. Always branch on the code, not on the message text.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"error": {
"code": "invalid_image",
"message": "The uploaded file could not be decoded as an image."
}
} | Hali ya HTTP | Msimbo wa hitilafu | Maana |
|---|---|---|
| 400 | bad_request | Ombi limeundwa vibaya, kwa mfano hakuna picha iliyotumwa au mwili wa JSON si sahihi. |
| 401 | unauthorized | Ufunguo wa API haupo au si sahihi. |
| 403 | forbidden | Barua pepe ya mmiliki wa ufunguo haijathibitishwa, usajili wa jarida umezimwa, au akaunti imepigwa marufuku. |
| 413 | file_too_large | Picha ni kubwa kuliko MB 10. |
| 415 | unsupported_type | Aina ya faili au aina ya maudhui ya ombi haitumiki. |
| 422 | invalid_image | Faili haikuweza kusomwa kama picha, au URL ya picha haikuweza kupakuliwa. |
| 429 | rate_limited | Maombi mengi mno. Subiri hadi X-RateLimit-Reset. |
| 500 | server_error | Hitilafu imetokea upande wetu. Jaribu tena baadaye; wasiliana na usaidizi tatizo likiendelea. |
Faili za matokeo
With all groups enabled, a package contains the files below. Files from disabled groups are left out.
| Faili | Ukubwa | Kundi |
|---|---|---|
favicon.ico | 16, 32, 48 (inaweza kusanidiwa) | daima |
favicon-16x16.png | 16 × 16 | favicon |
favicon-32x32.png | 32 × 32 | favicon |
favicon-96x96.png | 96 × 96 | favicon |
apple-icon-57x57.png | 57 × 57 | apple |
apple-icon-60x60.png | 60 × 60 | apple |
apple-icon-72x72.png | 72 × 72 | apple |
apple-icon-76x76.png | 76 × 76 | apple |
apple-icon-114x114.png | 114 × 114 | apple |
apple-icon-120x120.png | 120 × 120 | apple |
apple-icon-144x144.png | 144 × 144 | apple |
apple-icon-152x152.png | 152 × 152 | apple |
apple-icon-180x180.png | 180 × 180 | apple |
apple-icon.png | 192 × 192 | apple |
apple-icon-precomposed.png | 192 × 192 | apple |
apple-touch-icon.png | 180 × 180 | apple |
android-icon-36x36.png | 36 × 36 | android |
android-icon-48x48.png | 48 × 48 | android |
android-icon-72x72.png | 72 × 72 | android |
android-icon-96x96.png | 96 × 96 | android |
android-icon-144x144.png | 144 × 144 | android |
android-icon-192x192.png | 192 × 192 | android |
android-icon-512x512.png | 512 × 512 | android |
web-app-manifest-192x192.png | 192 × 192 | android |
web-app-manifest-512x512.png | 512 × 512 | android |
maskable-icon-512x512.png | 512 × 512 | android |
ms-icon-70x70.png | 70 × 70 | ms |
ms-icon-144x144.png | 144 × 144 | ms |
ms-icon-150x150.png | 150 × 150 | ms |
ms-icon-310x310.png | 310 × 310 | ms |
Faili za ziada
| Faili | Imejumuishwa | Maelezo |
|---|---|---|
favicon.svg | Kwa ingizo la SVG pekee bila kukata, kukuza, nafasi ya pembeni, pembe au mandharinyuma | Nakala iliyosafishwa ya SVG yako kwa vivinjari vinavyotumia favicon za vekta. |
manifest.json, site.webmanifest | android | Manifest ya programu ya wavuti kwa Android na PWA zinazoweza kusakinishwa (nakala mbili zinazofanana). |
browserconfig.xml | ms | Usanidi wa vigae vya Windows wenye rangi ya kigae chako. |
readme-makefav.txt | daima | Maelekezo ya usakinishaji yenye msimbo wa HTML wa <head> yako mwishoni. |
Mifano ya msimbo
Each example uploads logo.png with a few options and saves favicons.zip, handling API errors. Set the environment variable MAKEFAV_API_KEY to your API key first.
Kupakia kwa multipart:
# Multipart upload (recommended). --fail-with-body exits non-zero on HTTP errors
# and still saves the JSON error body, so you can inspect it.
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } Mwili wa JSON wenye picha iliyosimbwa kwa base64 (inahitaji jq):
# JSON body with a base64-encoded image (built with jq to avoid argument length limits)
base64 < logo.png | tr -d '\n' > logo.b64
jq -n --rawfile img logo.b64 \
'{image_base64: $img, app_name: "My App", theme_color: "#2f9e68", radius: 20}' \
| curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @- \
-o favicons.zip \
|| { echo "Request failed:"; cat favicons.zip; rm -f favicons.zip; exit 1; } <?php
// Requires the curl extension. Run: MAKEFAV_API_KEY=mf_... php favicons.php
$apiKey = getenv('MAKEFAV_API_KEY') ?: exit("Set MAKEFAV_API_KEY first\n");
$ch = curl_init('https://makefav.com/api/v1/generate');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $apiKey],
CURLOPT_POSTFIELDS => [
'image' => new CURLFile('logo.png', 'image/png', 'logo.png'),
'app_name' => 'My App',
'theme_color' => '#2f9e68',
'radius' => '20',
],
]);
$body = curl_exec($ch);
if ($body === false) {
fwrite(STDERR, 'Request failed: ' . curl_error($ch) . PHP_EOL);
exit(1);
}
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($status !== 200) {
$error = json_decode($body, true)['error'] ?? ['code' => 'http_' . $status, 'message' => substr($body, 0, 200)];
fwrite(STDERR, "Error {$status} {$error['code']}: {$error['message']}" . PHP_EOL);
exit(1);
}
file_put_contents('favicons.zip', $body);
echo 'Saved favicons.zip (' . strlen($body) . " bytes)\n"; # pip install requests · Run: MAKEFAV_API_KEY=mf_... python favicons.py
import os
import sys
import requests
API_KEY = os.environ["MAKEFAV_API_KEY"]
try:
with open("logo.png", "rb") as logo:
resp = requests.post(
"https://makefav.com/api/v1/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"image": ("logo.png", logo, "image/png")},
data={"app_name": "My App", "theme_color": "#2f9e68", "radius": 20},
timeout=60,
)
except requests.RequestException as exc:
sys.exit(f"Request failed: {exc}")
if resp.status_code != 200:
try:
err = resp.json()["error"]
sys.exit(f"Error {resp.status_code} {err['code']}: {err['message']}")
except (ValueError, KeyError, TypeError):
sys.exit(f"Error {resp.status_code}: {resp.text[:200]}")
with open("favicons.zip", "wb") as out:
out.write(resp.content)
remaining = resp.headers.get("X-RateLimit-Remaining")
print(f"Saved favicons.zip ({len(resp.content)} bytes), {remaining} requests left this hour") // favicons.mjs — Node.js 18+, no dependencies. Run: MAKEFAV_API_KEY=mf_... node favicons.mjs
import { readFile, writeFile } from 'node:fs/promises';
const form = new FormData();
form.append('image', new Blob([await readFile('logo.png')], { type: 'image/png' }), 'logo.png');
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
const res = await fetch('https://makefav.com/api/v1/generate', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.MAKEFAV_API_KEY}` },
body: form,
});
if (!res.ok) {
const body = await res.json().catch(() => null);
console.error(`Error ${res.status} ${body?.error?.code ?? ''}: ${body?.error?.message ?? res.statusText}`);
process.exit(1);
}
await writeFile('favicons.zip', Buffer.from(await res.arrayBuffer()));
console.log(`Saved favicons.zip, ${res.headers.get('x-ratelimit-remaining')} requests left this hour`); <input type="file" id="logo" accept="image/*">
<button type="button" id="go">Generate favicons</button>
<script>
// Never put your API key in browser code. Point ENDPOINT at your own backend route,
// which forwards the multipart body to https://makefav.com/api/v1/generate and adds
// the "Authorization: Bearer mf_..." header on the server.
const ENDPOINT = '/my-backend/favicons';
document.getElementById('go').addEventListener('click', async () => {
const file = document.getElementById('logo').files[0];
if (!file) {
alert('Please choose an image first.');
return;
}
const form = new FormData();
form.append('image', file);
form.append('app_name', 'My App');
form.append('theme_color', '#2f9e68');
form.append('radius', '20');
try {
const res = await fetch(ENDPOINT, { method: 'POST', body: form });
if (!res.ok) {
const body = await res.json().catch(() => null);
throw new Error(body?.error?.message || `HTTP ${res.status}`);
}
const url = URL.createObjectURL(await res.blob());
const a = Object.assign(document.createElement('a'), { href: url, download: 'favicons.zip' });
document.body.append(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
} catch (err) {
alert('Favicon generation failed: ' + err.message);
}
});
</script> // go run favicons.go (MAKEFAV_API_KEY must be set)
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/textproto"
"os"
"time"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
func run() error {
var body bytes.Buffer
w := multipart.NewWriter(&body)
logo, err := os.ReadFile("logo.png")
if err != nil {
return err
}
h := make(textproto.MIMEHeader)
h.Set("Content-Disposition", `form-data; name="image"; filename="logo.png"`)
h.Set("Content-Type", "image/png")
part, err := w.CreatePart(h)
if err != nil {
return err
}
if _, err := part.Write(logo); err != nil {
return err
}
for k, v := range map[string]string{"app_name": "My App", "theme_color": "#2f9e68", "radius": "20"} {
if err := w.WriteField(k, v); err != nil {
return err
}
}
if err := w.Close(); err != nil {
return err
}
req, err := http.NewRequest(http.MethodPost, "https://makefav.com/api/v1/generate", &body)
if err != nil {
return err
}
req.Header.Set("Authorization", "Bearer "+os.Getenv("MAKEFAV_API_KEY"))
req.Header.Set("Content-Type", w.FormDataContentType())
client := &http.Client{Timeout: 60 * time.Second}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
var apiErr struct {
Error struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"error"`
}
_ = json.NewDecoder(resp.Body).Decode(&apiErr)
return fmt.Errorf("error %d %s: %s", resp.StatusCode, apiErr.Error.Code, apiErr.Error.Message)
}
zip, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
if err := os.WriteFile("favicons.zip", zip, 0o644); err != nil {
return err
}
fmt.Printf("Saved favicons.zip (%d bytes)\n", len(zip))
return nil
} # ruby favicons.rb (MAKEFAV_API_KEY must be set) — standard library only
require "net/http"
require "json"
require "uri"
uri = URI("https://makefav.com/api/v1/generate")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch("MAKEFAV_API_KEY")}"
res = File.open("logo.png", "rb") do |logo|
req.set_form(
[
["image", logo, { filename: "logo.png", content_type: "image/png" }],
["app_name", "My App"],
["theme_color", "#2f9e68"],
["radius", "20"]
],
"multipart/form-data"
)
Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
end
unless res.is_a?(Net::HTTPSuccess)
err = (JSON.parse(res.body)["error"] rescue nil) || { "code" => res.code, "message" => res.body.to_s[0, 200] }
abort "Error #{res.code} #{err["code"]}: #{err["message"]}"
end
File.binwrite("favicons.zip", res.body)
puts "Saved favicons.zip (#{res.body.bytesize} bytes)" // .NET 6+ console app (Program.cs, top-level statements, implicit usings enabled)
using System.Net.Http.Headers;
using System.Text.Json;
using var http = new HttpClient { Timeout = TimeSpan.FromSeconds(60) };
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("MAKEFAV_API_KEY"));
using var form = new MultipartFormDataContent();
var image = new ByteArrayContent(await File.ReadAllBytesAsync("logo.png"));
image.Headers.ContentType = new MediaTypeHeaderValue("image/png");
form.Add(image, "image", "logo.png");
form.Add(new StringContent("My App"), "app_name");
form.Add(new StringContent("#2f9e68"), "theme_color");
form.Add(new StringContent("20"), "radius");
using var response = await http.PostAsync("https://makefav.com/api/v1/generate", form);
if (!response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
string code = "", message = body;
try
{
var error = JsonDocument.Parse(body).RootElement.GetProperty("error");
code = error.GetProperty("code").GetString() ?? "";
message = error.GetProperty("message").GetString() ?? "";
}
catch (Exception e) when (e is JsonException or KeyNotFoundException or InvalidOperationException) { }
Console.Error.WriteLine($"Error {(int)response.StatusCode} {code}: {message}");
return 1;
}
await File.WriteAllBytesAsync("favicons.zip", await response.Content.ReadAsByteArrayAsync());
Console.WriteLine("Saved favicons.zip");
return 0; // Java 11+, no dependencies. Run: MAKEFAV_API_KEY=mf_... java MakeFav.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
public class MakeFav {
public static void main(String[] args) throws IOException, InterruptedException {
String boundary = "----MakeFav" + UUID.randomUUID().toString().replace("-", "");
Map<String, String> fields = new LinkedHashMap<>();
fields.put("app_name", "My App");
fields.put("theme_color", "#2f9e68");
fields.put("radius", "20");
// Build the multipart/form-data body by hand
ByteArrayOutputStream body = new ByteArrayOutputStream();
for (Map.Entry<String, String> field : fields.entrySet()) {
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"" + field.getKey() + "\"\r\n\r\n"
+ field.getValue() + "\r\n").getBytes(StandardCharsets.UTF_8));
}
body.write(("--" + boundary + "\r\n"
+ "Content-Disposition: form-data; name=\"image\"; filename=\"logo.png\"\r\n"
+ "Content-Type: image/png\r\n\r\n").getBytes(StandardCharsets.UTF_8));
body.write(Files.readAllBytes(Path.of("logo.png")));
body.write(("\r\n--" + boundary + "--\r\n").getBytes(StandardCharsets.UTF_8));
HttpRequest request = HttpRequest.newBuilder(URI.create("https://makefav.com/api/v1/generate"))
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer " + System.getenv("MAKEFAV_API_KEY"))
.header("Content-Type", "multipart/form-data; boundary=" + boundary)
.POST(HttpRequest.BodyPublishers.ofByteArray(body.toByteArray()))
.build();
HttpResponse<byte[]> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofByteArray());
if (response.statusCode() != 200) {
// Error body is JSON: {"error":{"code":"...","message":"..."}}
System.err.println("Error " + response.statusCode() + ": "
+ new String(response.body(), StandardCharsets.UTF_8));
System.exit(1);
}
Files.write(Path.of("favicons.zip"), response.body());
System.out.println("Saved favicons.zip (" + response.body().length + " bytes)");
}
} Mtiririko wa GitHub Actions – muundo wa JSON, faili zikisimbuliwa kwa jq:
# .github/workflows/favicons.yml — regenerate favicons whenever the logo changes.
# Add your key as a repository secret named MAKEFAV_API_KEY.
name: Favicons
on:
push:
paths: ['branding/logo.png']
workflow_dispatch:
jobs:
favicons:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate favicon package (JSON format)
env:
MAKEFAV_API_KEY: ${{ secrets.MAKEFAV_API_KEY }}
run: |
set -euo pipefail
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "image=@branding/logo.png" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-F "path=/icons/" \
-F "format=json" \
-o favicons.json || { cat favicons.json; exit 1; }
mkdir -p public/icons
# Decode every file from the JSON response (jq is preinstalled on GitHub runners)
jq -r '.files[] | "\(.name) \(.base64)"' favicons.json |
while read -r name data; do
printf '%s' "$data" | base64 -d > "public/icons/$(basename "$name")"
done
jq -r '.html' favicons.json > public/icons/head-snippet.html
ls -l public/icons
- uses: actions/upload-artifact@v4
with:
name: favicons
path: public/icons Hati rahisi ya shell kwa CI yoyote – muundo wa ZIP:
#!/usr/bin/env bash
# scripts/favicons.sh — simpler variant for any CI or build step: fetch the ZIP and unpack it.
set -euo pipefail
: "${MAKEFAV_API_KEY:?Set MAKEFAV_API_KEY}"
curl --fail-with-body -sS https://makefav.com/api/v1/generate \
-H "Authorization: Bearer $MAKEFAV_API_KEY" \
-F "[email protected]" \
-F "app_name=My App" \
-F "theme_color=#2f9e68" \
-F "radius=20" \
-o favicons.zip || { cat favicons.zip; rm -f favicons.zip; exit 1; }
unzip -o -q favicons.zip -d public/
rm favicons.zip
echo "Favicons written to public/" Matumizi ya HTML
Upload all files to the folder you set with path, then paste the snippet into the <head> of every page. It is included at the end of readme-makefav.txt in the package and, with format=json, returned in the html field. Example for the options used in the code examples above:
<head>
<meta charset="utf-8">
<title>My App</title>
<link rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="manifest" href="/manifest.json">
<meta name="msapplication-TileColor" content="#2f9e68">
<meta name="msapplication-TileImage" content="/ms-icon-144x144.png">
<meta name="msapplication-config" content="/browserconfig.xml">
<meta name="theme-color" content="#2f9e68">
</head> Baada ya kupeleka, futa akiba ya kivinjari chako au fungua tovuti katika dirisha la faragha – vivinjari huhifadhi favicon kwa nguvu.
Orodha ya mabadiliko
v1
- Toleo la kwanza la umma la MakeFav REST API.
- Endpoints
POST /generate,GET /me,GET /sizesandGET /openapi.json. - Miundo ya jibu ya ZIP na JSON, multipart, base64 na ingizo la picha kwa URL.
- Funguo binafsi za API zenye maombi 100 kwa saa.
Toleo la 1 ni thabiti: tunaongeza tu vigezo na sehemu za hiari. Mabadiliko yanayovunja yatatolewa kama toleo jipya kwa taarifa ya mapema.
Msaada
Una maswali, ripoti za hitilafu au unahitaji kikomo cha juu zaidi? Tuko tayari kusaidia. Tafadhali weka muda wa ombi na msimbo wa hitilafu katika ujumbe wako – kamwe usiweke ufunguo wako wa API.