/* anladigim kadariyla, soyle bisey yapmak istiyorsunuz, | |
Sizin backend servisiniz (feather ile yazilmis) , Backend-Service diyelim, | |
bir de baska bir external service endpoint var , Backend-external diyelim. | |
Son olarak birde front-end olacak bunada front-end-client. | |
Sizin yapmak istediginizde , eger yanlis anlamadiysam, | |
1 - Backend-Service ve front-end-client in birebir bagli olmasi ve real-time olarak bagli kalmasi | |
2- Backend-external in da bu surecte ilgili oldugu kisimlari update olarak alabilmesi. | |
Burda, sizin backend-service iniz, olusturdugunuz feathers service araciligiyla aslinda bir proxy gorevi yapmis olacak, | |
sizin gonderdiginiz 1.yazida ki sekliyle yazmaniz yeterli. | |
(backend-external da, sizin disinizda yapilan degisikleri dinleyip, onlarida backend-service ve front-end-client a | |
aktarmak biraz farkli bi durum, cunku backend-external a erisimiz, nasil bilmiyorum. ordan her guncelleme icin size bir, | |
bildirim yapiliyormu mesela? event, web socket, web hook call vs gibi. Yoksa sadece o endpointe http request gonderme imkaniniz mi var?) | |
1.kisim kolay, zaten feathers size gerekli alt yapiyi sunuyor, | |
Sizin feather ile yazdiginiz backend e bagli olan tum istemciler feather client araciligiyla, backend e baglanip, | |
butun default(create, delete vs) eventlerini ve sizin ekleyeceginiz custom eventleri dinleyebilirler. | |
(belirli client lara yada sadece, belirli kullanicilara gondermek icinde channel lari kullanabilirsiniz.) | |
https://docs.feathersjs.com/api/events.html#eventemitters | |
feathers, bu eventleri siz bilerek kapatmadiginiz surece, otomatik olarak tum bagli istemcilere yayinlar(publish/broadcast) | |
siz sadece feather client araciligiyla bunlari dinlersiniz, | |
https://docs.feathersjs.com/api/client.html , client olarak websocket veya rest adapater den birini veya ikisinide beraber kullanabilirsiniz. | |
(@feathersjs/socketio-client' ve/veya @feathersjs/rest-client ) | |
ornegin front-end de dinlemek icin | |
feathers client i initialize ettik den sonra, ilgili service i service.event.callback signature ile dinleyebilirsiniz, | |
const messageService = client.service('messages'); | |
messageService.on('created', message => console.log('Created a message', message)); | |
burdaki linkden bakabilirsiniz. https://docs.feathersjs.com/api/client.html | |
2.kisim icin biraz daha bilgiye ihtiyac var, tam olarak bisey soyleyebilmek icin. | |
external-service deki sizin disinizda yapilan degisiklikleri de dinlemek istiyormusunuz? | |
bu external-service e sadece siz veri gondermek lemi ilgineyiorsunuz | |
eger dogru anladiysam ve ikinci soruya biraz daha aciklik getirirseniz, bir ornek olusturabilirim. | |
*/ | |
// Eger, authantication i ayarlamadiysaniz henuz, socket eventlerini dinlemek icin | |
// channel.js deki asagidaki satiri simdilik yoru mhaline getirip | |
// //return app.channel('authenticated'); | |
// bunu ekleyin, | |
// return app.channel('anonymous'); | |
// boylece baglantili tum istemciler, oturum acip acmadikalrina bakmadan | |
// eventleri dinleyebilirler. | |
// | |
/** Ornek external service ve custom event*/ | |
const httpClient = require("axios");// request modulu yerine, axios u tercih edebilirsiniz, daha hizli ve kolaydir. | |
/* eslint-disable no-unused-vars */ | |
exports.ExternalProduct = class ExternalProduct { | |
constructor (options) { | |
this.options = options || {}; | |
this.events = ['newProductAdded']; | |
httpClient.defaults.baseURL = 'https://api.example.com/api'; | |
// httpClient.defaults.headers.common['Authorization'] = "AUTH_TOKEN"; | |
httpClient.defaults.headers.common['Content-Type'] = "application/json"; | |
this.httpAuthOptions = { | |
username: 'admin_email', | |
password: 'auto-generated API key' | |
}; | |
this.startPolling() | |
} | |
async find (params) { | |
return httpClient.get("/products",{auth:this.httpAuthOptions}); | |
} | |
async get (id, params) { | |
return httpClient.get(`/products/${id}`,{auth:this.httpAuthOptions}); | |
} | |
async create (data, params) { | |
return httpClient.post(`/products`,data,{auth:this.httpAuthOptions}); | |
/* if (Array.isArray(data)) { | |
return Promise.all(data.map(current => this.create(current, params))); | |
} | |
return data; | |
*/ | |
} | |
async update (id, data, params) { | |
return httpClient.put(`/products/${id}`,data,{auth:this.httpAuthOptions}); | |
} | |
async patch (id, data, params) { | |
return httpClient.patch(`/products`,data,{auth:this.httpAuthOptions}); | |
} | |
async remove (id, params) { | |
return httpClient.delete(`/products/${id}`,{auth:this.httpAuthOptions}); | |
// return { id }; | |
} | |
startPolling() { | |
// her 10 dakikada bir external service i sorgula ve | |
// eger bir guncelleme varsa, bunu istemcileri ilet. | |
let lastUpdated = Date.now(); | |
let queryUrl = `/products?lastUpdated=${lastUpdated}`; | |
httpClient | |
.get(queryUrl,{auth:this.httpAuthOptions}) | |
.then(data =>{ | |
this.emit('newProductAdded',{data}); | |
setTimeout(()=> this.startPolling(), 600000 )//10 minutes in miliseconds | |
}) | |
.catch(err =>{ | |
console.log("error polling", err); | |
setTimeout(()=> this.startPolling(), 600000 ) | |
}) | |
} | |
}; | |
/** **/ | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<title>A FeathersJS application</title> | |
<meta name="description" content="A FeathersJS server"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" | |
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> | |
<style> | |
body { | |
padding: 20px; | |
} | |
</style> | |
</head> | |
<body > | |
<main id="app"> | |
<div class="container"> | |
<div class="row"> | |
<div class="col-6"> | |
<h3>My products</h3> | |
<table class="table table-striped table-hover"> | |
<thead> | |
<tr> | |
<th>#</th> | |
<th>Id</th> | |
<th>Title</th> | |
<th>Price</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr v-for="(product, index) in myProducts"> | |
<td>{{index}}</td> | |
<td>{{product._id}}</td> | |
<td>{{product.title}}</td> | |
<td>{{product.price}}</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
<div class="col-6"> | |
<h3>External products </h3> | |
<table class="table table-striped table-hover table-dark"> | |
<thead> | |
<tr> | |
<th>#</th> | |
<th>Id</th> | |
<th>Title</th> | |
<th>Price</th> | |
</tr> | |
</thead> | |
<tbody> | |
<tr v-for="(product, index) in externalProducts"> | |
<td>{{index}}</td> | |
<td>{{product.id}}</td> | |
<td>{{product.title}}</td> | |
<td>{{product.price}}</td> | |
</tr> | |
</tbody> | |
</table> | |
</div> | |
</div> | |
<footer> | |
</footer> | |
</div> | |
</main> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/core-js/2.1.4/core.min.js"></script> | |
<script src="//unpkg.com/@feathersjs/client@^3.0.0/dist/feathers.js"></script> | |
<script src="//unpkg.com/socket.io-client@1.7.3/dist/socket.io.js"></script> | |
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> | |
<script> | |
const feathersClient = feathers(); | |
const socket = io('http://localhost:3030'); | |
feathersClient.configure(feathers.socketio(socket)); | |
//app.configure(feathers.authentication()); | |
const app = new Vue({ | |
el: '#app', | |
data: { | |
myProducts:[], | |
externalProducts:[], | |
socketClient:undefined | |
}, | |
mounted () { | |
axios | |
.get('/my-product') | |
.then(response => { | |
this.myProducts = response.data.data; | |
}) | |
.catch(err => { | |
console.log(err); | |
}); | |
axios | |
.get('/demo-external-products') | |
.then(response => { | |
this.externalProducts = response.data.data; | |
console.log(response.data) | |
}) | |
.catch(err => { | |
console.log(err); | |
}); | |
feathersClient.service('my-product').on('created', (data) => { | |
console.log(data); | |
this.myProducts.push(data) | |
}); | |
feathersClient.service('my-product').on('removed', (data) => { | |
console.log("Deleted:",data) | |
this.myProducts = this.myProducts.filter(p => p._id!=data._id) | |
}); | |
feathersClient.service('my-product').on('updated', (data) => { | |
console.log("Deleted:",data) | |
this.myProducts = this.myProducts.map(p =>{ | |
if (p._id==data._id) return data | |
return p; | |
}) | |
}); | |
feathersClient.service('external-product').on('created', (data) => { | |
console.log(data) | |
this.externalProducts.push(data) | |
}) | |
feathersClient.service('external-product').on('newProductAdded', (data) => { | |
console.log(data) | |
}) | |
} | |
}) | |
</script> | |
</body> | |
</html> | |
/** Ornek fronted | |
*// |
This comment has been minimized.
This comment has been minimized.
Merhaba,
Yine external service icinde ayni mantik gecerli, servisinizi, feathers signature daki gibi yazarsaniz, onun icinde otomatik olarak event ler publish edilecegi icin, yine 1.de oldugu gibi bagli tum istemcilerden dinleyebilirsiniz. external service orneginde , feathers in eventleri otomatik publish etmesi icin ilgili methodlarin calismasi yeterli olacaktir. Bir baska secenekte eger direkt olarak dinleyen degilde sizin bildirim gondermeniz gerekenler varsa, en kolay yolu, service hook lar ile yapmaktir bunu. her service methodu icin ayri ayri hook yazbailirsiniz, bunun icinde bir ornek ekledim.
yani berlirli bir aralikla external servisi sorgulayip yeni bisey varmi yok mu sizin kendiniz kontrol etmeniz gerekiyor. Ornegin benim sorguladigim bir cok external api da bunun icin query ye 'lastUpdated={timestap|fulldate}' benzeri bir field eklemenize imkan veriyor boylelikle 100% real time olmasada belirli araliklarla sorgulama yapip guncellemeleri almaniza imkan veriyor, Tabi tarz bi sorgunun , sizin hedefinizde olan, external service tarafindan desteklenip, desteklenmedigini bilmiyorum Kolay gelsin |
This comment has been minimized.
This comment has been minimized.
@Nrhn , bu arada yukaridakileri yazarken sizin, Fetahers cli i kullanarak projenizi olsturdugunuzu varsaydim. |
This comment has been minimized.
This comment has been minimized.
proje.zip
<https://drive.google.com/file/d/1dG3DjnXZuuDPlNnbnKv9deCQ-tMm7R2T/view?usp=drive_web>
hdd <notifications@github.com>, 10 Eki 2019 Per, 18:44 tarihinde şunu yazdı:
… @Nrhn <https://github.com/Nrhn> , bu arada yukaridakileri yazarken sizin,
Fetahers cli i kullanarak projenizi olsturdugunuzu varsaydim.
https://docs.feathersjs.com/guides/basics/generator.html
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<https://gist.github.com/478e3e263818e09e99a296a43206d08e?email_source=notifications&email_token=AMG3KS2BPZF6MIVZ5D7G67DQN5EUVA5CNFSM4I63CNDKYY3PNVWWK3TUL52HS4DFVNDWS43UINXW23LFNZ2KUY3PNVWWK3TUL5UWJTQAF2INI#gistcomment-3051732>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AMG3KS6PWMX73Q7WVESR5VLQN5EUVANCNFSM4I63CNDA>
.
|
This comment has been minimized.
This comment has been minimized.
Merhaba, https://github.com/hdd42/feathers-demo client => vue client , cd client && npm install && npm run serve bayadir , vue js ile calismadigim icin, bazi seyleri unutmusum, ama sanirim size fikir verecek kadar olmustur. 3 uygulmayida calistirdiktan sonra, (vue client, feathers api ve external demo) , bir den fazla tarayici acip real time iletisimi test edip izleyebilirsiniz, ornek ekran goruntusu : insallah yardimci olur |
This comment has been minimized.
Bu kısım yaptım ve çalışır halde fakat eksikler çok :) event listenerlar yine burda da eksik henüz.
Benim şuan yapmak istediğim aşama tam olarak bu.
API hakkında genel bilgi:
Uses Basic HTTP authentication, with admin e-mail as login and auto-generated API key as password
Relies on user group-defined privileges. User group assignment is defined directly in the objects
Uses HTTP 1.1 to implement REST.
4 methods are available to view and modify objects:
GET—get object data
PUT—update object data
POST—create new object
DELETE—delete object
Accepts and returns data in JSON format
Create Object (POST):
To create an object, send a POST HTTP request to the URL that refers to the according object type.
Only URLs referring to a whole object type (without ID) can be used.
The submitted data must be a JSON array of keys and values for the object fields (e.g. {'fieldName1: value1, fieldName2: value2}.)
Some fields are mandatory for object creating. Refer to the API objects page for a complete list of supported fields for all supported objects.
The header Content-Type must be declared and set to application/json, otherwise the default text/plain is assumed and the request will fail.
Request Example
curl --user admin@example.com:APIkey --header 'Content-Type: application/json' -d '{"product": "My Awesome Product"}' -X POST 'http://example.com/api/products'
Created object ID, e.g. {"product_id":"1"}, or an error.
Developer guide'da sadece http requestler için REST API başlığı bulabildim. çok saçma gelebilir bu soru ama bu API websocket gibi realtime olanakları sağlamıyorsa yapmak istediğim işlemi REST ile realtime bir çözüme ulaştırabilir miyim?
"2.kisim icin biraz daha bilgiye ihtiyac var, tam olarak bisey soyleyebilmek icin.
external-service deki sizin disinizda yapilan degisiklikleri de dinlemek istiyormusunuz?
bu external-service e sadece siz veri gondermek lemi ilgineyiorsunuz"
Bu iki soru çok iyi oldu gerçekten, tşk ederim. Bunu hiç düşünmemiştim çünkü şuan farkediyorum. Benim yaptığım değişiklikleri kesinlikle dinlemek istiyorum diye aklımdaydı fakat benim dışımdaki değişiklikleri dinlemekte mümkünse ve yapılabılıyorsa yapıp öğrenmek isterim.