```html
Web geliştirmenin hızla gelişen dünyasında, doğru framework'ü bulmak zorlayıcı olabilir. Hızlı, hafif ve farklı ortamlarda çalışacak kadar esnek bir şey istersiniz. İşte Hono – etkileyici hızı, minimum ayak izi ve geliştirici dostu tasarımıyla geliştiriciler arasında hızla popülerlik kazanan bir web framework'ü.
Hono (Japonca'da "alev" 🔥 anlamına gelir) adını hak ediyor – son derece hızlı ve zarif sadeliğiyle geliştirme deneyiminizi aydınlatıyor. İster API'ler, ister mikro hizmetler veya full-stack uygulamalar oluşturuyor olun, Hono daha ağır framework'lere cazip bir alternatif sunuyor.
Bu rehber, Hono.js'ye kurulumdan ilk uygulamanızı oluşturmaya ve temel kavramlarını anlamaya kadar bilmeniz gereken her şeyi size adım adım anlatacak.
Geliştirici Ekibinizin maksimum verimlilikle birlikte çalışması için entegre, Hepsi Bir Arada bir platform mu istiyorsunuz?
Apidog tüm taleplerinizi karşılıyor ve Postman'in yerini çok daha uygun bir fiyata alıyor!
Hono Nedir?

Hono, Web Standartları üzerine inşa edilmiş küçük, basit ve ultra hızlı bir web framework'üdür. Neredeyse her JavaScript çalışma zamanında çalışır: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge ve Node.js.
Temelinde Hono, Web Standartları API'lerini (Request, Response ve Fetch gibi) benimser, bu da ona platformlar arasında dikkate değer bir taşınabilirlik sağlar. Bu, kodunuzu bir kez yazıp büyük değişiklikler yapmadan neredeyse her yere dağıtabileceğiniz anlamına gelir.
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => c.text('Hono!'))
export default app
Bu basit örnek, Express'ten ilham alan ancak günümüzün JavaScript ekosistemi için modernize edilmiş Hono'nun temiz sözdizimini göstermektedir.
Hadi dalalım!
1. Hono.js'yi Bun ile Kurun ve Proje Kurulumu
Bun, bir paket yöneticisi, paketleyici ve test çalıştırıcısı dahil olmak üzere hızı ve hepsi bir arada araç takımıyla bilinen modern bir JavaScript çalışma zamanıdır. Hono'yu Bun ile kurmak basittir.
Önkoşullar
Bun'un yüklü olduğundan emin olun. Değilse, resmi Bun web sitesindeki talimatları izleyerek yükleyebilirsiniz.
Bun ile Yeni Bir Hono Projesi Oluşturma
Bun ile yeni bir Hono projesine başlamanın en hızlı yolu, create-hono
iskele oluşturma aracını kullanmaktır:
bun create hono@latest my-hono-app
Bu komut, bir şablon seçmenizi ister. Bu rehber için bun
şablonunu seçin.
? Which template do you want to use? › - Use arrow keys. Return to submit.
❯ bun
cloudflare-workers
cloudflare-pages
deno
fastly
netlify
nodejs
vercel
Şablonu seçtikten sonra, yeni proje dizininize gidin ve bağımlılıkları yükleyin:
cd my-hono-app
bun install
Hono'yu Mevcut Bir Bun Projesine Ekleme
Mevcut bir Bun projeniz varsa, Hono'yu bir bağımlılık olarak ekleyebilirsiniz:
bun add hono
2. Hono.js ile Temel Bir Uygulama Oluşturma: "Merhaba Hono!"
Basit bir "Merhaba Dünya" (ya da daha doğrusu, "Merhaba Hono!") uygulaması oluşturalım.
Projenizin içinde bir src
dizini olmalıdır. src/index.ts
'yi (veya düz JavaScript tercih ediyorsanız index.js
'yi, ancak Hono'nun tüm avantajları için TypeScript önerilir) oluşturun veya açın.
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono!')
})
export default app
Bunu parçalayalım:
hono
paketindenHono
sınıfını içe aktarıyoruz.Hono
'nun yeni bir örneğini oluşturuyoruz, genellikleapp
olarak adlandırılır.- Kök yola (
/
) yapılanGET
istekleri için bir rota tanımlıyoruz. - Rota işleyicisi, bir
Context
nesnesini (geleneksel olarakc
) bir argüman olarak alan bir fonksiyondur. c.text('Hello Hono!')
, "Merhaba Hono!" metnini içeren bir Response nesnesi oluşturur.- Son olarak,
app
örneğini dışa aktarıyoruz. Bun için, bu varsayılan dışa aktarım, geliştirme sunucusunun onu alması için yeterlidir.
Uygulamanızı Çalıştırma
Uygulamanızı geliştirme modunda çalıştırmak için, package.json
dosyanızda tanımlanan dev
komut dosyasını kullanın (create-hono
bunu sizin için ayarlar):
bun run dev
Bu genellikle bir sunucuyu http://localhost:3000
adresinde başlatır. Bu URL'yi web tarayıcınızda açın; "Merhaba Hono!" görmelisiniz.
Portu Değiştirme
Uygulamanızı farklı bir portta çalıştırmanız gerekiyorsa, src/index.ts
içindeki dışa aktarımı değiştirebilirsiniz:
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono on port 8080!')
})
export default {
port: 8080, // İstediğiniz portu belirtin
fetch: app.fetch,
}
Şimdi, bun run dev
komutunu çalıştırdığınızda, uygulama http://localhost:8080
adresinde hizmet verecektir.
3. Hono.js ile Temel Bir API Oluşturma
Hono, API'ler oluşturmada mükemmeldir. Yönlendirmeyi ve istekleri nasıl işleyeceğimizi ve yanıtlar oluşturacağımızı inceleyelim.
Yönlendirme
Hono'da yönlendirme sezgiseldir. app
örneği, HTTP fiillerine karşılık gelen yöntemlere sahiptir (.get()
, .post()
, .put()
, .delete()
, vb.).
Temel GET Rotası
Zaten temel bir GET rotası gördük:
app.get('/hello', (c) => {
return c.text('Hello, world!')
})
Yol Parametreleri
:paramName
sözdizimini kullanarak yol parametreleri olan rotalar tanımlayabilirsiniz. Bu parametrelere c.req.param('paramName')
aracılığıyla erişilebilir.
// Örnek: /users/123
app.get('/users/:id', (c) => {
const userId = c.req.param('id')
return c.text(`User ID: ${userId}`)
})
Sorgu Parametreleri
URL'den gelen sorgu parametrelerine (örneğin, /search?q=hono
) c.req.query('queryName')
kullanılarak erişilebilir.
// Örnek: /search?category=frameworks&limit=10
app.get('/search', (c) => {
const category = c.req.query('category')
const limit = c.req.query('limit')
return c.text(`Searching in category: ${category}, Limit: ${limit}`)
})
Ayrıca, tüm sorgu parametrelerini c.req.query()
ile bir nesne olarak alabilirsiniz.
Farklı HTTP Yöntemlerini İşleme
Hono, aynı yol için çeşitli HTTP yöntemlerini işlemeyi kolaylaştırır:
// src/index.ts
import { Hono } from 'hono'
const app = new Hono()
// GET a list of posts
app.get('/posts', (c) => {
// Gerçek bir uygulamada, bunu bir veritabanından alırsınız
const posts = [
{ id: '1', title: 'Getting Started with Hono' },
{ id: '2', title: 'Advanced Hono Techniques' },
];
return c.json(posts); // JSON yanıtı döndür
})
// GET a single post by ID
app.get('/posts/:id', (c) => {
const id = c.req.param('id')
// Fetch post by ID from a database
const post = { id: id, title: `Post ${id}`, content: 'This is the content...' };
if (!post) {
return c.notFound() // 404 için yerleşik yardımcı
}
return c.json(post)
})
// CREATE a new post
app.post('/posts', async (c) => {
const body = await c.req.json() // JSON gövdesini ayrıştır
// Gerçek bir uygulamada, bunu bir veritabanına kaydedersiniz
console.log('Creating post:', body)
return c.json({ message: 'Post created successfully!', data: body }, 201) // 201 Created ile yanıt ver
})
// UPDATE an existing post
app.put('/posts/:id', async (c) => {
const id = c.req.param('id')
const body = await c.req.json()
// Update post in database
console.log(`Updating post ${id}:`, body)
return c.json({ message: `Post ${id} updated successfully!`, data: body })
})
// DELETE a post
app.delete('/posts/:id', (c) => {
const id = c.req.param('id')
// Delete post from database
console.log(`Deleting post ${id}`)
return c.json({ message: `Post ${id} deleted successfully!` })
})
export default {
port: 3000,
fetch: app.fetch
}
İstek Nesnesi (c.req
)
Context
nesnesi (c
), c.req
aracılığıyla istek ayrıntılarına erişim sağlar. Temel özellikleri ve yöntemleri şunlardır:
c.req.url
: Tam URL dizesi.c.req.method
: HTTP yöntemi (örneğin, 'GET', 'POST').c.req.headers
: Bir Headers nesnesi.c.req.header('Content-Type')
gibi başlıklar erişin.c.req.param('name')
: Bir yol parametresi alın.c.req.query('name')
: Bir sorgu parametresi alın.c.req.queries('name')
: Tekrarlanan bir sorgu parametresi için tüm değerleri bir dizi olarak alın.c.req.json()
: İstek gövdesini JSON olarak ayrıştırır. (Bir Promise döndürür)c.req.text()
: İstek gövdesini düz metin olarak okur. (Bir Promise döndürür)c.req.arrayBuffer()
: İstek gövdesini bir ArrayBuffer olarak okur. (Bir Promise döndürür)c.req.formData()
: İstek gövdesini FormData olarak ayrıştırır. (Bir Promise döndürür)c.req.valid('type')
: Doğrulanmış verilere erişin (daha sonra ele alınacak doğrulayıcılarla kullanılır).
Yanıt Nesnesi (c
) ve Yardımcılar
Context
nesnesi (c
) ayrıca Response
nesneleri oluşturmak için kullanışlı yardımcılar sağlar:
c.text(text, status?, headers?)
: Düz metin yanıtı döndürür.c.json(object, status?, headers?)
: JSON yanıtı döndürür.Content-Type
otomatik olarakapplication/json
olarak ayarlanır.c.html(html, status?, headers?)
: HTML yanıtı döndürür.c.redirect(location, status?)
: Yönlendirme yanıtı döndürür (varsayılan durum 302).c.notFound()
: 404 Not Found yanıtı döndürür.c.newResponse(body, status?, headers?)
: Yeni birResponse
nesnesi oluşturur.body
null
,ReadableStream
,ArrayBuffer
,FormData
,URLSearchParams
veyastring
olabilir.c.header(name, value)
: Bir yanıt başlığı ayarlar.
Örnek: Özel Başlıklar Ayarlama
app.get('/custom-header', (c) => {
c.header('X-Powered-By', 'HonoJS-Flame')
c.header('Cache-Control', 'no-cache')
return c.text('Check the response headers!')
})
4. Hono.js'de Middleware ile Çalışmak
Middleware fonksiyonları, Hono'nun (ve birçok web framework'ünün) temel taşıdır. Bunlar, bir isteği ana rota işleyicisine ulaşmadan önce veya işleyici çalıştıktan sonra bir yanıtı işleyebilen fonksiyonlardır. Middleware, günlüğe kaydetme, kimlik doğrulama, veri doğrulama, sıkıştırma, CORS ve daha fazlası gibi görevler için harikadır.
Bir middleware fonksiyonunun temel imzası async (c, next) => { ... }
'dir.
c
: Context nesnesi.next
: Zincirdeki bir sonraki middleware'e veya son rota işleyicisine kontrolü geçirmek için çağrılacak bir fonksiyon. Sonraki middleware'in veya işleyicinin yürütülmesini istiyorsanızawait next()
kullanmalısınız.
Yerleşik Middleware'i Kullanma
Hono, zengin bir yerleşik middleware kümesiyle birlikte gelir. Bunları hono/middleware-name
'den (örneğin, hono/logger
, hono/cors
) içe aktarabilirsiniz.
Middleware'i tüm rotalara uygulamak için app.use(middlewareFunction)
kullanın.
Middleware'i belirli rotalara uygulamak için ilk argüman olarak bir yol deseni sağlayın: app.use('/admin/*', authMiddleware)
.
Örnek: Logger ve ETag Middleware
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { etag } from 'hono/etag'
import { prettyJSON } from 'hono/pretty-json' // Güzelce biçimlendirilmiş JSON yanıtları için
const app = new Hono()
// Middleware'i tüm rotalara uygula
app.use(logger()) // İstek ve yanıt bilgilerini konsola kaydeder
app.use(etag()) // Önbelleğe alma için ETag başlıkları ekler
app.use(prettyJSON()) // JSON yanıtlarını girintilerle biçimlendirir
app.get('/', (c) => {
return c.text('Hello with Logger and ETag!')
})
app.get('/data', (c) => {
return c.json({ message: 'This is some data.', timestamp: Date.now() })
})
export default app
Bunu çalıştırdığınızda ve /
veya /data
'ya eriştiğinizde, konsolunuzda günlükleri göreceksiniz ve yanıtlar bir ETag
başlığı içerecektir. /data
'dan gelen JSON yanıtları güzelce biçimlendirilecektir.
Diğer Faydalı Yerleşik Middleware:
cors
: Çapraz Kaynak Paylaşımını (CORS) işler.basicAuth
: Temel Kimlik Doğrulamayı uygular.jwt
: JWT (JSON Web Token) kimlik doğrulaması.compress
: Yanıt gövdelerini sıkıştırır.cache
: Önbelleğe alma API'sini kullanarak önbelleğe almayı uygular.secureHeaders
: Çeşitli güvenlikle ilgili HTTP başlıkları ekler.bodyLimit
: İstek gövdesinin boyutunu sınırlar.
"Middleware" altında Hono belgelerinde tam bir liste ve dokümantasyon bulabilirsiniz.
Özel Middleware Oluşturma
Kendi middleware'inizi kolayca yazabilirsiniz.
Örnek 1: Basit İstek Zamanlayıcısı
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
const app = new Hono()
app.use(logger())
// İstek işleme süresini ölçmek için özel middleware
app.use(async (c, next) => {
const start = Date.now()
console.log(`Request received at: ${new Date(start).toISOString()}`)
await next() // Bir sonraki middleware'i veya rota işleyicisini çağırın
const ms = Date.now() - start
c.header('X-Response-Time', `${ms}ms`) // Yanıta özel başlık ekleyin
console.log(`Request processed in ${ms}ms`)
})
app.get('/', (c) => {
return c.text('Hello from Hono with custom timing middleware!')
})
app.get('/slow', async (c) => {
// Yavaş bir işlemi simüle et
await new Promise(resolve => setTimeout(resolve, 1500))
return c.text('This was a slow response.')
})
export default app
Zamanlama günlüklerini ve X-Response-Time
başlığını görmek için /
ve /slow
'a erişin.
Örnek 2: Basit API Anahtarı Kimlik Doğrulama Middleware'i
Bu, gösteri amaçlı çok basit bir örnektir. Gerçek bir uygulamada, JWT veya OAuth gibi daha sağlam kimlik doğrulama yöntemleri kullanın ve API anahtarlarını güvenli bir şekilde saklayın.
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { HTTPException } from 'hono/http-exception' // Standart HTTP hataları atmak için
const app = new Hono()
app.use(logger())
const API_KEY = "supersecretapikey"; // Gerçek bir uygulamada, bunu güvenli bir şekilde saklayın (örneğin, env değişkeni)
// Özel API Anahtarı Kimlik Doğrulama Middleware'i
const apiKeyAuth = async (c, next) => {
const apiKeyHeader = c.req.header('X-API-KEY')
if (apiKeyHeader && apiKeyHeader === API_KEY) {
await next()
} else {
// Standart bir hata yanıtı döndürmek için HTTPException kullanma
throw new HTTPException(401, { message: 'Unauthorized: Invalid API Key' })
}
}
// Bu middleware'i belirli bir rota grubuna uygulayın
app.use('/api/v1/*', apiKeyAuth)
app.get('/api/v1/me', (c) => {
return c.json({ user: 'Authenticated User', email: 'user@example.com' })
})
app.get('/public/info', (c) => {
return c.text('This is public information, no API key needed.')
})
// HTTPException için hata işleyici
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse()
}
// Diğer hatalar için
console.error('Unhandled error:', err)
return c.text('Internal Server Error', 500)
})
export default app
Bunu test etmek için:
curl http://localhost:3000/api/v1/me
(401 Yetkisiz döndürmelidir)curl -H "X-API-KEY: supersecretapikey" http://localhost:3000/api/v1/me
(kullanıcı verilerini döndürmelidir)curl http://localhost:3000/public/info
(genel bilgileri döndürmelidir)
createMiddleware
ile Özel Middleware'i Yeniden Kullanma
Daha karmaşık veya yeniden kullanılabilir middleware için, hono/factory
'den createMiddleware
kullanarak ayrı olarak tanımlayabilirsiniz. Bu aynı zamanda TypeScript tür çıkarımına da yardımcı olur.
// src/middlewares/timing.ts
import { createMiddleware } from 'hono/factory'
export const timingMiddleware = createMiddleware(async (c, next) => {
const start = Date.now()
await next()
const ms = Date.now() - start
c.res.headers.set('X-Response-Time', `${ms}ms`) // Not: c.res.headers.set
console.log(` -> Processed in ${ms}ms`)
})
// src/middlewares/auth.ts
import { createMiddleware } from 'hono/factory'
import { HTTPException } from 'hono/http-exception'
const VALID_API_KEY = "anothersecretkey";
// Middleware'inizin ihtiyacı varsa ortam değişkenleri için tür
type Env = {
Variables: {
user?: { id: string } // Örnek: kimlik doğrulama sonrası kullanıcı verilerini ayarlayın
}
// Bindings: { MY_KV_NAMESPACE: KVNamespace } // Örnek: Cloudflare Workers için
}
export const secureApiKeyAuth = createMiddleware<Env>(async (c, next) => {
const apiKey = c.req.header('Authorization')?.replace('Bearer ', '')
if (apiKey === VALID_API_KEY) {
// İsteğe bağlı olarak, alt akış işleyicileri için bağlamda değişkenler ayarlayabilirsiniz
c.set('user', { id: 'user123' })
await next()
} else {
throw new HTTPException(401, { message: 'Access Denied: Secure API Key Required.'})
}
})
// src/index.ts
import { Hono } from 'hono'
import { logger } from 'hono/logger'
import { timingMiddleware } from './middlewares/timing' // Middlewares klasöründe olduklarını varsayarak
import { secureApiKeyAuth } from './middlewares/auth'
const app = new Hono()
app.use(logger())
app.use(timingMiddleware) // Tüm rotalara uygula
app.get('/', (c) => {
return c.text('Hello from Hono with factored middleware!')
})
app.use('/secure/data/*', secureApiKeyAuth) // Yalnızca /secure/data/* için uygula
app.get('/secure/data/profile', (c) => {
// const user = c.get('user') // Middleware tarafından ayarlanan değişkene erişin
return c.json({ profileData: 'Sensitive profile information', /*user: user*/ })
})
app.get('/public/data', (c) => {
return c.text('This is public data, no key needed.')
})
// Genel hata işleyici
app.onError((err, c) => {
if (err instanceof HTTPException) {
return err.getResponse();
}
console.error('Error:', err.message);
return c.json({ error: 'Internal Server Error', message: err.message }, 500);
});
export default app
Bu yapı, middleware'inizi daha modüler hale getirir ve bağımsız olarak test etmeyi kolaylaştırır.
5. Hono.js Uygulamalarınızı Test Etme
Hono, kolayca test edilebilir olacak şekilde tasarlanmıştır. Bun, Hono ile iyi çalışan kendi test çalıştırıcısı bun:test
ile birlikte gelir. Ayrıca Vitest gibi diğer test çalıştırıcılarını da kullanabilirsiniz.
bun:test
'i Kullanma (Temel)
bun.md
dokümantasyonu, bun:test
ile test etmenin temel bir örneğini sağlar:
Örneğin, src/index.test.ts
adlı bir test dosyası oluşturun:
// src/index.test.ts
import { describe, expect, it } from 'bun:test'
import app from '.' // Uygulamanızı src/index.ts'den içe aktarır
describe('Hono Uygulama Testleri', () => {
it('GET / için 200 OK döndürmelidir', async () => {
const req = new Request('http://localhost/') // Temel URL burada çok önemli değil
const res = await app.fetch(req)
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hello Hono!') // Veya kök rotanızın döndürdüğü her neyse
})
it('GET /posts için JSON döndürmelidir', async () => {
const req = new Request('http://localhost/posts')
const res = await app.fetch(req)
expect(res.status).toBe(200)
const json = await res.json()
expect(json).toBeArray() // /posts bir dizi döndürdüğünü varsayarak
// Gerekirse JSON içeriği hakkında daha özel iddialar ekleyin
})
it('POST /posts için bir gönderi oluşturmalıdır', async () => {
const postData = { title: 'Test Post', content: 'This is a test.' };
const req = new Request('http://localhost/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(postData),
});
const res = await app.fetch(req);
expect(res.status).toBe(201); // 201 Created bekleyin
const jsonResponse = await res.json();
expect(jsonResponse.message).toBe('Post created successfully!');
expect(jsonResponse.data.title).toBe(postData.title);
});
})
Testlerinizi çalıştırmak için:
bun test
Veya, belirli bir dosyayı çalıştırmak istiyorsanız:
bun test src/index.test.ts
app.request()
Yardımcısını Kullanma
Hono, her seferinde tam bir Request
nesnesi oluşturmak yerine, doğrudan bir yol ve seçenekler geçirmenize izin vererek test etmeyi basitleştiren kullanışlı bir app.request()
yöntemi sağlar. Bu, docs/guides/testing.md
'de gösterilmektedir.
// src/index.test.ts
import { describe, expect, it } from 'bun:test' // Veya 'vitest'ten içe aktarın
import app from '.' // Hono uygulamanızın örneği
describe('app.request() ile Hono Uygulaması', () => {
it('GET / "Merhaba Hono!" döndürmelidir', async () => {
const res = await app.request('/')
expect(res.status).toBe(200)
expect(await res.text()).toBe('Hello Hono!') // Kök yanıtınıza göre ayarlayın
})
it('GET /posts/:id belirli bir gönderiyi döndürmelidir', async () => {
// Uygulamanızın app.get('/posts/:id', ...) gibi bir rotası olduğunu varsayarak
// ve bu test için, { id: '123', title: 'Test Post 123' } döndürebilir
const res = await app.request('/posts/123')
expect(res.status).toBe(200)
const data = await res.json()
expect(data.id).toBe('123')
// expect(data.title).toBe('Post 123') // Veya uygulamanızın mantığına göre
})
it('POST /posts yeni bir gönderi oluşturmalıdır', async () => {
const newPost = { title: 'My New Post', content: 'Awesome content here.' }
const res = await app.request('/posts', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(newPost),
})
expect(res.status).toBe(201) // POST /posts'unuzun 201 döndürdüğünü varsayarak
const responseData = await res.json()
expect(responseData.message).toBe('Post created successfully!')
expect(responseData.data.title).toBe(newPost.title)
})
it('API anahtarı olmadan GET /api/v1/me 401 olmalıdır', async () => {
// Önceki örnekten API anahtarı middleware'inin bu rotada etkin olduğunu varsayarak
const res = await app.request('/api/v1/me')
expect(res.status).toBe(401)
})
it('Doğru API anahtarıyla GET /api/v1/me 200 olmalıdır', async () => {
const res = await app.request('/api/v1/me', {
headers: {
'X-API-KEY': 'supersecretapikey' // Middleware'inizden anahtarı kullanın
}
})
expect(res.status).toBe(200)
const data = await res.json();
expect(data.user).toBe('Authenticated User')
})
})