Teie ettevõte käivitas just oma API ja soovib nüüd selle ümber ehitada kasutajate kogukonna. Teate, et enamik teie kliente töötab JavaScripti , kuna teie API pakutavad teenused muudavad klientide jaoks lihtsamaks veebirakenduste loomise, selle asemel et kõik ise kirjutada - Twilio on selle hea näide.
Teate ka, et see on sama lihtne kui teie RESTful API võib olla, kasutajad soovivad langeda JavaScripti paketti see teeb nende jaoks kogu raske tõste. Nad ei taha teie API-d õppida ja iga vajaminevat taotlust ise koostada.
Nii et teete oma API ümber raamatukogu. Või kirjutate võib-olla lihtsalt oma sisemise API-ga suhtleva veebirakenduse olekusüsteemi.
Mõlemal juhul ei soovi te ennast korrata iga kord, kui teete oma API-ressurssidele halba, või mis veelgi hullem, CRUD-i nende ressurssidega seotud ressurssi. See pole hea kasvava SDK haldamiseks pikas perspektiivis ega ole ka teie aja hea kasutamine.
kuidas pythonit rahanduses kasutatakse
Selle asemel võite kasutada ActiveResource.js , JavaScripti ORM-süsteem API-dega suhtlemiseks. Lõin selle projekti vajaduse täitmiseks: JavaScripti SDK loomiseks võimalikult vähestel ridadel. See võimaldas nii meie kui ka meie arendajate kogukonna jaoks maksimaalset efektiivsust.
See põhineb Ruby on Railsi lihtsa ActiveRecord ORM-i põhimõtetel.
ActiveResource.js kujundamisel juhindub kahest Ruby on Rails ideest:
Product
ressurss, vastab see /products
lõpp-punkt. Nii ei kuluta aega korduvalt teie SDK kõigi taotluste konfigureerimist teie API-le. Arendajad saavad teie kasvavasse SDK-sse lisada uusi keerukate CRUD-päringutega API-ressursse minutite, mitte tundide jooksul.Oluline on märkida, et selle kirjutamise ajal töötab ActiveResource.js ainult API-dega, mis on kirjutatud vastavalt JSON: API standard .
Kui te pole JSON: API-ga tuttav ja soovite kaasa minna, siis neid on palju häid raamatukogusid JSON: API serveri loomiseks.
See tähendab, et ActiveResource.js on pigem DSL kui ümbris ühe konkreetse API standardi jaoks. Kasutajaliidest, mida ta kasutab teie API-ga suhtlemiseks, saab laiendada, nii et tulevased artiklid võiksid käsitleda ActiveResource.js-i kasutamist kohandatud API-ga.
Alustuseks installige active-resource
oma projektis:
yarn add active-resource
Esimene samm on luua ResourceLibrary
teie API jaoks. Panen kõik oma ActiveResource
s src/resources
kaust:
// /src/resources/library.js import { createResourceLibrary } from 'active-resource'; const library = createResourceLibrary('http://example.com/api/v1'); export default library;
Ainus nõutav parameeter createResourceLibrary
on teie API juur-URL.
Loome sisuhaldussüsteemi API jaoks JavaScripti SDK kogu. See tähendab, et seal on kasutajaid, postitusi, kommentaare ja märguandeid.
Kasutajad saavad postitusi lugeda, luua ja redigeerida; lugeda, lisada ja kustutada kommentaare (postituste või muude kommentaaride jaoks) ning saada teateid uute postituste ja kommentaaride kohta.
Ma ei hakka vaate (React, Angular jne) ega oleku (Redux jne) haldamiseks kasutama ühtegi konkreetset teeki, selle asemel, et õpetust abstraktselt kasutada, et suhelda ainult teie API-ga ActiveResource
s kaudu.
Alustame User
loomisega ressurss CMS-i kasutajate haldamiseks.
Kõigepealt loome User
ressursiklassi attributes
:
// /src/resources/User.js import library from './library'; class User extends library.Base { static define() { this.attributes('email', 'userName', 'admin'); } } export default library.createResource(User);
Oletame praegu, et teil on autentimise lõpp-punkt, mis pärast kasutaja e-posti aadressi ja parooli esitamist tagastab juurdepääsuloa ja kasutaja ID. Seda lõpp-punkti haldab mõni funktsioon requestToken
Kui olete saanud autentitud kasutajatunnuse, soovite laadida kõik kasutaja andmed.
import library from '/src/resources/library'; import User from '/src/resources/User'; async function authenticate(email, password) { let [accessToken, userId] = requestToken(email, password); library.headers = { Authorization: 'Bearer ' + accessToken }; return await User.find(userId); }
Seadsin library.headers
omada Authorization
päis koos accessToken
nii et kõik minu ResourceLibrary
tulevased taotlused on volitatud.
Hilisemas jaotises käsitletakse, kuidas kasutajat autentida ja pääsuluba seadistada, kasutades ainult User
ressursside klass.
authenticate
. Viimane samm on taotlus User.find(id)
. See taotleb /api/v1/users/:id
ja vastus võib välja näha umbes:
{ 'data': { 'type': 'users', 'id': '1', 'attributes': { 'email': ' [email protected] ', 'user_name': 'user1', 'admin': false } } }
authenticate
Vastus on User
eksemplar klass. Siit saate juurde pääseda autentitud kasutaja erinevatele atribuutidele, kui soovite neid kuskil rakenduses kuvada.
let user = authenticate(email, password); console.log(user.id) // '1' console.log(user.userName) // user1 console.log(user.email) // [email protected] console.log(user.attributes()) /* { email: ' [email protected] ', userName: 'user1', admin: false } */
Kõik atribuutide nimed muutuvad camelCasediks, et need sobiksid JavaScripti tüüpiliste standarditega. Igaüks neist saab otse user
omadustena objekti või hankige kõik atribuudid, helistades user.attributes()
Enne kui lisame veel ressursse, mis on seotud User
klassi, näiteks teatised, peaksime lisama faili src/resources/index.js
, mis indekseerib kõik meie ressursid. Sellel on kaks eelist:
src/resources
mitme ressursi jaoks ühes impordilauses, selle asemel et kasutada mitut impordilauset.ResourceLibrary
-s loome helistades library.createResource
igaühel, mis on vajalik ActiveResource.js jaoks suhete loomiseks.// /src/resources/index.js import User from './User'; export { User };
Nüüd loome seotud ressursi User
, a Notification
Kõigepealt looge Notification
klass, mis belongsTo
User
klass:
// /src/resources/Notification.js import library from './library'; class Notification extends library.Base { static define() { this.belongsTo('user'); } } export default library.createResource(Notification);
Seejärel lisame selle ressursside indeksisse:
// /src/resources/index.js import Notification from './Notification'; import User from './User'; export { Notification, User };
Seejärel seostage teatised User
-ga klass:
// /src/resources/User.js class User extends library.Base { static define() { /* ... */ this.hasMany('notifications'); } }
Nüüd, kui oleme kasutaja tagasi teenusest authenticate
tagasi saanud, saame kõik selle märguanded laadida ja kuvada:
let notifications = await user.notifications().load(); console.log(notifications.map(notification => notification.message));
Autentitud kasutaja algsesse taotlusse võime lisada ka teatised:
async function authenticate(email, password) { /* ... */ return await User.includes('notifications').find(userId); }
See on üks paljudest DSL-is pakutavatest võimalustest.
Vaatame nüüd juba kirjutatud koodist selle, mida on juba võimalik taotleda.
Võite esitada päringu kasutajate kogu või ühe kasutaja kohta.
let users = await User.all(); let user = await User.first(); user = await User.last(); user = await User.find('1'); user = await User.findBy({ userName: 'user1' });
Päringut saate muuta aheldatavate relatsioonimeetodite abil:
// Query and iterate over all users User.each((user) => console.log(user)); // Include related resources let users = await User.includes('notifications').all(); // Only respond with user emails as the attributes users = await User.select('email').all(); // Order users by attribute users = await User.order({ email: 'desc' }).all(); // Paginate users let usersPage = await User.page(2).perPage(5).all(); // Filter users by attribute users = await User.where({ admin: true }).all(); users = await User .includes('notifications') .select('email', { notifications: ['message', 'createdAt'] }) .order({ email: 'desc' }) .where({ admin: false }) .perPage(10) .page(3) .all(); let user = await User .includes('notification') .select('email') .first();
Pange tähele, et saate päringu koostada mis tahes hulga aheldatud modifikaatorite abil ja saate päringu lõpetada .all()
, .first()
, .last()
või .each()
.
Saate kasutaja üles ehitada kohapeal või luua selle serverisse:
let user = User.build(attributes); user = await User.create(attributes);
Kui teil on püsiv kasutaja, saate selle muudatused saata serverisse salvestamiseks:
user.email = ' [email protected] '; await user.save(); /* or */ await user.update({ email: ' [email protected] ' });
Samuti saate selle serverist kustutada:
await user.destroy();
See põhiline DSL laieneb ka seotud ressurssidele, nagu demonstreerin ülejäänud juhendaja jooksul. Nüüd saame rakenduse ActiveResource.js kiiresti ülejäänud CMS-i loomiseks rakendada: postitused ja kommentaarid.
Looge ressursi klass Post
jaoks ja seostage see User
-ga klass:
// /src/resources/Post.js import library from './library'; class Post extends library.Base { static define() { this.belongsTo('user'); } } export default library.createResource(Post);
// /src/resources/User.js class User extends library.Base { static define() { /* ... */ this.hasMany('notifications'); this.hasMany('posts'); } }
Lisa Post
ka ressursside indeksisse:
// /src/resources/index.js import Notification from './Notification'; import Post from './Post'; import User from './User'; export { Notification, Post, User };
Seejärel siduge Post
ressurss vormi, kus kasutajad saavad postitusi luua ja redigeerida. Kui kasutaja külastab esimest korda uue postituse loomise vormi, kuvatakse a Post
ressurss ehitatakse ja iga kord, kui vormi muudetakse, rakendame muudatuse Post
import Post from '/src/resources/Post'; let post = Post.build({ user: authenticatedUser }); onChange = (event) => { post.content = event.target.value; };
Järgmisena lisage onSubmit
vormi tagasihelistamine postituse serverisse salvestamiseks ja vigade käsitsemiseks, kui salvestamise katse ebaõnnestub:
onSubmit = async () => { try { await post.save(); /* successful, redirect to edit post form */ } catch { post.errors().each((field, error) => { console.log(field, error.message) }); } }
Kui postitus on salvestatud, lingitakse see teie serveris oleva ressursina teie API-ga. Kui ressurss on serveris püsinud, saate teada helistades persisted
if (post.persisted()) { /* post is on server */ }
Püsivate ressursside korral toetab ActiveResource.js määrdunud atribuute, et saaksite kontrollida, kas ressursi mõnda atribuuti on serveris selle väärtusest muudetud.
kuidas kasutada node js-i
Kui helistate save()
püsiva ressursi korral teeb see PATCH
päring, mis sisaldab ainult ressursis tehtud muudatusi, selle asemel, et kogu ressursi atribuutide ja seoste komplekt asjatult serverile edastada.
Jälgitud atribuute saate ressursile lisada, kasutades attributes
deklaratsioon. Jälgime muudatusi post.content
// /src/resources/Post.js class Post extends library.Base { static define() { this.attributes('content'); /* ... */ } }
Nüüd saame serveri püsiva postitusega postitust muuta ja kui nupul Esita klõpsatakse, salvestage muudatused serverisse. Saame ka nupu Esita keelata, kui muudatusi pole veel tehtud:
onEdit = (event) => { post.content = event.target.value; } onSubmit = async () => { try { await post.save(); } catch { /* display edit errors */ } } disableSubmitButton = () => { return !post.changed(); }
Ainsuse seose haldamiseks on meetodeid, näiteks post.user()
, kui soovisime postitusega seotud kasutajat muuta:
await post.updateUser(user);
See on samaväärne järgmisega:
await post.update({ user });
Nüüd looge ressursside klass Comment
ja seostage see Post
-ga. Pidage meeles meie nõuet, et kommentaarid võivad olla vastus postitusele või mõnele muule kommentaarile, nii et kommentaari asjakohane ressurss on polümorfne:
// /src/resources/Comment.js import library from './library'; class Comment extends library.Base { static define() { this.attributes('content'); this.belongsTo('resource', { polymorphic: true, inverseOf: 'replies' }); this.belongsTo('user'); this.hasMany('replies', { as: 'resource', className: 'Comment', inverseOf: 'resource' }); } } export default library.createResource(Comment);
Lisage kindlasti Comment
kuni /src/resources/index.js
samuti.
Peame Post
juurde lisama rea klass ka:
// /src/resources/Post.js class Post extends library.Base { static define() { /* ... */ this.hasMany('replies', { as: 'resource', className: 'Comment', inverseOf: 'resource' }); } }
inverseOf
valik edastati hasMany
mõiste replies
määratlus näitab, et see seos on polümorfse belongsTo
pöördväärtus mõiste resource
määratlus. inverseOf
suhete omadusi kasutatakse suhete vaheliste toimingute tegemisel sageli. Tavaliselt määratakse see omadus automaatselt klassi nime kaudu, kuid kuna polümorfsed seosed võivad olla üks mitmest klassist, peate määratlema inverseOf
Polümorfsete seoste funktsionaalsus on tavaline.
Sama DSL, mis kehtib ressursside kohta, kehtib ka seotud ressursside haldamise kohta. Nüüd, kui oleme postituste ja kommentaaride vahelised suhted loonud, on selle suhte haldamiseks mitmeid viise.
Postitusele saate lisada uue kommentaari:
onSubmitComment = async (event) => { let comment = await post.replies().create({ content: event.target.value, user: user }); }
Kommentaarile saate lisada vastuse:
onSubmitReply = async (event) => { let reply = await comment.replies().create({ content: event.target.value, user: user }); }
Kommentaari saate muuta:
onEditComment = async (event) => { await comment.update({ content: event.target.value }); }
Saate postitusest kommentaari eemaldada:
onDeleteComment = async (comment) => { await post.replies().delete(comment); }
SDK-d saab kasutada lehitsetud postituste loendi kuvamiseks ja kui postitusel klõpsatakse, laaditakse postitus uuele lehele koos kõigi selle kommentaaridega:
import { Post } from '/src/resources'; let postsPage = await Post .order({ createdAt: 'desc' }) .select('content') .perPage(10) .all();
Ülaltoodud päring toob välja 10 viimast postitust ja optimeerimiseks on ainus laaditav atribuut nende content
.
Kui kasutaja klõpsab postituste järgmisele lehele liikumiseks nuppu, otsib muudatuste käitleja järgmise lehe. Siin keelame ka nupu, kui järgmisi lehti pole.
onClickNextPage = async () => { postsPage = await postsPage.nextPage(); if (!postsPage.hasNextPage()) { /* disable next page button */ } };
Kui klõpsatakse postituse lingil, avame uue lehe, laadides ja kuvades postituse koos kõigi selle andmetega, sealhulgas selle kommentaarid - tuntud kui vastused - ja vastused neile vastustele:
import { Post } from '/src/resources'; onClick = async (postId) => { let post = await Post.includes({ replies: 'replies' }).find(postId); console.log(post.content, post.createdAt); post.replies().target().each(comment => { console.log( comment.content, comment.replies.target().map(reply => reply.content).toArray() ); }); }
Helistamine .target()
kohta hasMany
suhe nagu post.replies()
tagastab ActiveResource.Collection
kommentaare, mis on kohapeal laaditud ja salvestatud.
See eristamine on oluline, sest post.replies().target().first()
tagastab esimese laaditud kommentaari. Seevastu post.replies().first()
tagastab lubaduse GET /api/v1/posts/:id/replies
-lt küsitud ühe kommentaari eest.
Samuti võite taotleda postituse vastuseid eraldi postituse päringust, mis võimaldab teil oma päringut muuta. Saate aheldada modifikaatoreid nagu order
, select
, includes
, where
, perPage
, page
päringu tegemisel hasMany
ressursside päringuid.
import { Post } from '/src/resources'; onClick = async (postId) => { let post = await Post.find(postId); let userComments = await post.replies().where({ user: user }).perPage(3).all(); console.log('Your comments:', userComments.map(comment => comment.content).toArray()); }
Mõnikord soovite enne kasutamist andmeid serverist võtta ja neid muuta. Näiteks võite pakkida post.createdAt
aastal moment()
objekt, et saaksite kuvada kasutaja jaoks kasutajasõbraliku kuupäeva postituse loomise ajast:
// /src/resources/Post.js import moment from 'moment'; class Post extends library.Base { static define() { /* ... */ this.afterRequest(function() { this.createdAt = moment(this.createdAt); }); } }
Kui töötate olekuhaldussüsteemiga, mis soosib muutumatuid objekte, saab ActiveResource.js-is kogu käitumise muuta ressursside kogu konfigureerimisel muutumatuks:
// /src/resources/library.js import { createResourceLibrary } from 'active-resource'; const library = createResourceLibrary( 'http://example.com/api/v1', { immutable: true } ); export default library;
Kokkuvõtteks näitan teile, kuidas integreerida oma kasutaja autentimissüsteem oma User
ActiveResource
.
Teisaldage oma luba autentimissüsteem API lõpp-punkti /api/v1/tokens
Kui sellele lõpp-punktile saadetakse kasutaja e-posti aadress ja parool, saadetakse vastuseks autentitud kasutaja andmed koos autoriseerimisloaga.
Looge Token
ressursside klass, mis kuulub User
:
// /src/resources/Token.js import library from './library'; class Token extends library.Base { static define() { this.belongsTo('user'); } } export default library.createResource(Token);
Lisa Token
kuni /src/resources/index.js
.
Seejärel lisage staatiline meetod authenticate
teie User
ressursiklassi ja seostada User
kuni Token
:
// /src/resources/User.js import library from './library'; import Token from './Token'; class User { static define() { /* ... */ this.hasOne('token'); } static async authenticate(email, password) { let user = this.includes('token').build({ email, password }); let authUser = await this.interface().post(Token.links().related, user); let token = authUser.token(); library.headers = { Authorization: 'Bearer ' + token.id }; return authUser; } }
See meetod kasutab resourceLibrary.interface()
, mis on antud juhul JSON: API liides, kasutaja saatmiseks /api/v1/tokens
. See kehtib: JSON-i lõpp-punkt: API ei nõua, et sinna ja sealt postitataks ainult tüüpe, mille järgi see on nime saanud. Seega on taotlus järgmine:
{ 'data': { 'type': 'users', 'attributes': { 'email': ' [email protected] ', 'password': 'password' } } }
Vastuseks saab autentitud kasutaja, kelle autentimiskood sisaldab:
{ 'data': { 'type': 'users', 'id': '1', 'attributes': { 'email': ' [email protected] ', 'user_name': 'user1', 'admin': false }, 'relationships': { 'token': { 'data': { 'type': 'tokens', 'id': 'Qcg6yI1a5qCxXgKWtSAbZ2MIHFChHAq0Vc1Lo4TX', } } } }, 'included': [{ 'type': 'tokens', 'id': 'Qcg6yI1a5qCxXgKWtSAbZ2MIHFChHAq0Vc1Lo4TX', 'attributes': { 'expires_in': 3600 } }] }
Siis kasutame token.id
meie raamatukogu Authorization
seadmiseks päise ja tagastab kasutaja, mis on sama, mis kasutajalt User.find()
nagu me enne tegime.
Nüüd, kui helistate User.authenticate(email, password)
, saate vastuseks autentitud kasutaja ja kõik tulevased taotlused autoriseeritakse juurdepääsuloa abil.
Selles õpetuses uurisime võimalusi, kuidas ActiveResource.js aitab teil kiiresti luua JavaScripti SDK teie API-ressursside ja nende erinevate, mõnikord keeruliste seotud ressursside haldamiseks. Kõiki neid ja rohkem dokumenteeritud funktsioone näete saidil README for ActiveResource.js .
Loodan, et teile on meeldinud nende toimingute lihtsus ja et kasutate (ja võib-olla isegi panustate) minu kogu oma tulevaste projektide jaoks, kui see sobib teie vajadustega. Avatud lähtekoodiga vaimus on PR-id alati teretulnud!
SDK tähistab tarkvaraarenduskomplekti, mis JavaScripti kontekstis tähendab sageli raamatukogu konkreetse REST API-ga suhtlemiseks.
ORM tähistab „objektide-relatsioonide kaardistamist“ - tehnikat objektidega töötamiseks, ilma et peaksime mõtlema, kust need pärinevad või kuidas neid hoitakse. Näiteks võib ORM-i teek eraldada API või vajaduse SQL-teadmiste järele, olenevalt sellest, millises kihis seda kasutatakse.
CRUD teenus, nt. põhiline REST API on see, mis pakub liidese toimingute „loomine, lugemine, värskendamine ja kustutamine” teostamiseks. Teisisõnu võimaldab see andmete salvestamise põhitoiminguid, mis vastavad SQL-i käskudele INSERT, SELECT, UPDATE ja DELETE ning HTTP-verbidele POST, GET, PUT / PATCH ja DELETE.
API pakub teenuse abstraktsiooni, hõlbustades sellega töötamist, eesmärgiga pääseda juurde laiemale programmeerijate rühmale. Näiteks võimaldab Trello API teil programmipõhiselt luua uusi Trello kaarte HTTP-päringute kaudu.
API-võti on taotluste sõnastamiseks kasutatav salajane märgis, mis võimaldab API-teenuse pakkujal taotlejat positiivselt tuvastada, eeldades, et see jääb saladuseks.
Sisuhaldus viitab üldiselt sisevõrgus või Internetis avaldatava tekstisisu loomisele ja korrastamisele. Viimase paari aasta jooksul on kõige populaarsem sisuhaldussüsteem (CMS) WordPress.
See on mõistete kokkuvõte, kuid viitab tõenäoliselt RDBMS-ile, nt SQL Server, MySQL või PostgreSQL. ORM-i tööriistad aitavad mõnikord objekte SQL-i back-endi kaardistada. ActiveResource.js võtab kokku teise kihi, kaardistades objektid REST API lõpp-punktidega.