Phoenix API uygulaması #1
- 1 — Phoenix proje oluşturma, kullanıcılar, ilk json endpoint
- 2 — Giriş yapma ve yetkilendirme, rotaları koruma
- 3 — E-posta göndererek kullanıcı teyit etme
- 4 — (Şu an buradasınız :) Swagger ile döküman üretme
Merhabalar, uzun bir süredir yan projelerde kullanarak öğrenmeye çalıştığım Elixir dili için bir rehber niteliğinde notlar paylaşacağım yazı serime hoş geldiniz. Bu yazıya sıklıkla Ruby on Rails ile karşlılaştırılmaları yapılan Phoenix web framework ile API-only bir uygulama yazma rehberi olarak bakabilirsiniz. Hazırsam başlayayım… :)
Yeni bir Phoenix projesi oluşturma
Bu adımda Elixir, Erlang ve Phoenix framework’ün sisteminizde kurulu olduğunu varsayıyorum. Değilse eğer sizi şuraya yönlendirebilirim.
Aşağıdaki komutu terminalimizde çalıştırarak bir phoenix projesi açalım.
mix phx.new app --no-html --no-webpack
--no-html
ve --no-webpack
flagleri projemizin bir front-endi olmadığını belirtiyor, ve phx.new
mix taskı da bunu anlayarak front-endsiz bir proje açıyor. Bu komut bulunduğunuz dizinde ./app
adında bir dizin açarak içine phoenix boilerplate’i yerleştirecektir. Peşine mix deps.get
taskını çalıştırarak bağımlılıkları indirecek ve dizinin içine girecektir.
Şimdi bir API uygulamasının olmazsa olmazı olan auth endpointlerinden başlayabiliriz.
Auth contexti ile User modeli
Öncelikle Auth
contexti altında User
data modelimizi oluşturalım.
mix phx.gen.context Auth User users name:string email:string:unique password_digest:string confirmed_at:datetime
Phoenix bu Auth
contexti altında User
data modelimizi oluştururken users
adında bir tablo oluşturmak için de gerekli migration dosyalarımızı priv/repo/migrations
dizini altına oluşturdu. password_digest
isimli string
olan alanımız bcrypt
ile şifrelemek için mix.exs
dosyasında deps
fonksiyonuna aşağıdaki hex paketini ekleyelim.
# Add bcrypt for pass hashing in mix.exs {:bcrypt_elixir, "~> 2.0"}
mix deps.get
komutunu çalıştırınca bcrypt_elixir
paketi hex.pm
den indirilerek yüklenecektir.
Bu arada testlerde performansı arttırmak amacı ile config/test.exs
konfigürasyon dosyasına aşağidaki ayarları ekleyerek bcrypt güvenlik seviyesini düşürelim.
# config/test.exs
config :bcrypt_elixir, :log_rounds, 4
lib/app/auth/user.ex
dosyasını açıp password
adında sanal bir field oluşturalım.
field :password, :string, virtual: true
field :password_digest, :string
virtual: true
bu field’ın veritabanında olmadığını belirtmektedir. Bu field’ı kullanıcı girdisi olarak alacağız ve üzerinde validasyonlarımızı yapıp, testlerimizden geçer ise password_digest
verisini bcrypt ile üreteceğiz.
Bunun için changeset
fonksiyonunu aşağıdaki gibi değiştirelim.
def changeset(user, attrs) do
user
|> cast(attrs, ~w(name email password confirmed_at)a)
|> validate_required(~w(name email password)a)
# E-mail validasyonu
|> unique_constraint(:email)
|> validate_format(:email, ~r/([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/)
# Password validasyonu (min 6 karakter ve confirmation ister)
|> validate_length(:password, min: 6)
|> validate_confirmation(:password)
# Changeset'e password_digest ekle
|> put_password_digest()
enddefp put_password_digest(
%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset) do
change(changeset, password_digest: Bcrypt.hash_pwd_salt(password)) enddefp put_password_digest(changeset), do: changeset
Yukarıda yorum satırlarında bahsettiğim gibi validasyonlarımız gerçekleşecek ve sıkıntısız changeset geldi ise bcrypt ile şifrelenmiş bir password_digest
değeri oluşacaktır.
Otomatik oluşturulan auth testleri bizim eklediklerimiz ile bozulduğu için orayı düzeltsek iyi olur. *_attrs
değerlerine bakınız…
CORS (Cross-Origin Resource Sharing)
API’ımıza hangi originlerden ve hangi methodlarla erişilebileceğini belirtmek ve ya kısıtlamak için mix.exs
e cors_plug
paketini ekliyoruz.
Ve ardından mix deps.get
ile paketi indirirken config/dev.exs
ve config/prod.exs
dosyalarında aşağıdaki tanımlamaları yapıyoruz.
# config/dev.exs
config :cors_plug,
origin: ~r/localhost/,
max_age: 86400, # 24 hours
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]# config/prod.exs
config :cors_plug,
origin: ["https://domain.com", "https://example.com"],
max_age: 86400, # 24 hours
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"]
İlk endpointimiz
Phoenix de aynı Rails gibi güzel generatorlere(mix tasks) sahip. Json endpointleri hazırlamak için aşağıdaki mix taskını kullanabiliriz.
mix phx.gen.json Auth User users name:string email:string password:string --no-context --no-schema# it asks for proceed that with existed Auth context, you can say [Y] * creating lib/app_web/controllers/user_controller.ex
* creating lib/app_web/views/user_view.ex
* creating test/app_web/controllers/user_controller_test.exs
* creating lib/app_web/views/changeset_view.ex
* creating lib/app_web/controllers/fallback_controller.ex Add the resource to your :api scope in lib/app_web/router.ex:
resources "/users", UserController, except: [:new, :edit]
router.ex
dosyamıza rotamızı ekleyelim.
scope "/api", AppWeb do
pipe_through :api
# ...
scope "/v1", V1 do
resources "/users", UserController, except: [:new, :edit]
end
end
Tarayıcımızdan http://localhost:4000/api/v1/users
adresine gidersek yeni rotamızı görebiliriz.
Tabi user_controller_test dosyamızı da testleri geçecek şekilde güncellemeyi de ihmal etmeyelim. Özellikle password fieldını gördüğümüz her yerden kaldıralım.
lib/app_web/views/user_view.ex
dosyasında da password
ü kaldırmayı unutmayalım.
Şimdi şuradan devam edebilirsiniz…
Originally published at murat.github.io on April 13, 2019.