Create-graphql-serverisascaffoldingtoolthatletsyougenerateanewMongo/Express/Node.jsGraphQLserverprojectfromthecommandline.AftergeneratingtheprojectyoucanalsogeneratecodetosupportyourGraphQLschemadirectlyfromtheschemafiles.BasicauthenticationsupportisincludedviaPassportLocalwithJWTs.
NOTE:thisprojectisnotactivelymaintained.Asascaffoldingtool,thisisnotnecessarilyanissue(youcangenerateaprojectwithitandthenforgetaboutthetool),butitisincreasinglyfallingoutofdate.Aspritiualsuccessoristhegraphql-cliproject.Pleasetakealook!
GettingStartedInstallationInstallitonceglobally:
npminstall-gcreate-graphql-serverCreatingaServerTocreateanewserverinthemy-new-server-dirfolderusetheinitcommand:
create-graphql-serverinitmy-new-server-dircdmy-new-server-diryarninstallStartingtheServerInmostdevelopmentenvironmentsyoucannowfireupyournewserverusingthepackagedprebuiltMongoserver:
yarnstartIfmongo-prebuiltfailstostart,oryou'dratheruseanotherMongoDBinstallationfordevelopment,simplysettheMONGO_URLenvironmentvariablewhenyoustarttheserver,asfollows:
#OnWindows:SETMONGO_URL=mongodb://localhost:27017&&yarnstart#OnUnix/OSX:MONGO_URL=mongodb://localhost:27017yarnstartIfyousetupausername,passwordoradifferentportforMongo,orareaccessingMongothroughaservicesuchasmLab,correcttheMONGO_URLabovetoreflectthat.
RunningQueriesYourserverisnowupandrunning.Toqueryit,pointyourbrowserathttps://localhost:3010/graphiql.Thereisn'tanythingtoqueryyethowever.
AddingTypes:OverviewToaddtypes,youcandefinetheminGraphQLschemafiles,thengeneratecodeforthemusingtheadd-typecommand,asfollows:
create-graphql-serveradd-typepath/to/my-new-type.graphqlIfyouhaveafolderfullofschemafiles,youcanaddthemallatoncebypointingadd-typetoafolderinsteadofanindividualschemafile:
create-graphql-serveradd-typepathSampleschemafilesareincludedintest/input.Toseewhatacompletegeneratedserverlookslikeusingthem,checkouttest/output-app.
SchemasYoucreateaGraphQLtypeforyourschemabyspecifyingthetypeasinput,withsomespecialcode-generationcontrollingdirectives.
Forexample,inUser.graphql:
typeUser{email:String!bio:Stringtweets:[Tweet!]@hasMany(as:"author")liked:[Tweet!]@belongsToManyfollowing:[User!]@belongsToManyfollowers:[User!]@hasAndBelongsToMany(as:"following")}TheabovewillgenerateaUsertypewhichislinkedtootherusersandatweettypeviaforiegnkeysandwhichwillhavemutationstoadd,updateandremoveusers,aswellassomerootqueriestofindasingleuserorallusers.
Thedirectivesusedcontrolthecodegeneration(seebelow).
Directives@unmodifiable-thefieldwillnotappearintheupdatemutation@enum-thefield'stypeisanenum,andcanbesetdirectly(notjustbyId).RelationsIftypesreferenceeachother,youshoulduseanassociationdirectivetoexplaintothegeneratorhowthereferenceshouldbestoredinmongo:
SingletonfieldsIfthefieldreferencesasingle(nullableorotherwise)instanceofanothertype,itwillbeeither:
@belongsTo-theforeignkeyisstoredonthistypeas${fieldName}Id[thisisthedefault]@hasOne-theforeignkeyisstoredonthereferencedtypeas${typeName}Id.Providethe"as":Xargumentifthenameisdifferent.[NOTE:thisisnotyetfullyimplemented].PaginatedfieldsIfthefieldreferencesanarray(againw/orw/onullability)ofanothertype,itwillbeeither:
@belongsToMany-thereisalistofforeignkeysstoredonthistypeas${fieldName}Ids[thisisthedefault]@hasMany-theforeignkeyisonthereferencedtypeas${typeName}Id.Providethe"as":Xargumentifthenameisdifferent.(thisisthereverseof@belongsToina1-manysituation).@hasAndBelongsToMany-theforeignkeyonthereferencedtypeas${typeName}Ids.Providethe"as":Xargumentifthenameisdifferent.(thisisthereverseof@belongsToManyinamany-manysituation).UpdatingtypesToupdatetypes,justre-runadd-typeagain:
create-graphql-serveradd-typepath/to/input.graphql[--force-update]Thisoverwritesyouroldtypespecificfilesfromthedirectories:schema,model,resolvers.
Itrecognizes,ifyou'vechangedanycodefile,whichwillbeoverwrittenbythegeneratorandstopsandwarns.Ifyouaresure,youwanttooverwriteyourchanges,thenjustusethe--force-updateoption.
RemovingtypesToremovetypes,usethefollowingcommandwiththepathtotheGraphQLfile,orasalternative,justenterthetypenamewithoutpath.
create-graphql-serverremove-typepath/to/input.graphqlcreate-graphql-serverremove-typetypenamecreate-graphql-serverremove-typepathThiscommanddeletesyouroldtypespecificfilesfromthedirectories:schema,model,resolvers.Italsoremovesthecodereferencesoutofthecorrespondingindexfiles.
Itrecognizes,ifyou'vechangedanycodefile,whichwillbeoverwrittenbythegeneratorandstopsandwarns.Ifyouaresure,youwanttooverwriteyourchanges,thenjustusetheforce-updateoption.
AuthenticationCGSsetsupabasicpassport-basedJWTauthenticationsystemforyourapp.
NOTE:youshouldensureusersconnecttoyourserverthroughSSL.
Touseit,ensureyouhaveaGraphQLtypecalledUserinyourschema,withafieldemail,bywhichuserswillbelookedup.Whencreatingusers,ensurethatabcryptedhashdatabasefieldisset.Forinstance,ifyoucreatedyourusersinthisway:
typeUser{email:String!bio:String}YoucouldupdatethegeneratedCreateUserInputinputobjecttotakeapasswordfield:
inputCreateUserInput{email:String!password:String!#<-youneedtoaddthislinetothegeneratedoutputbio:String}AndthenupdatethegeneratedUsermodeltohashthatpasswordandstoreit:
importbcryptfrom'bcrypt';//SetthisasappropriateconstSALT_ROUNDS=10;classUser{asyncinsert(doc){//Wedon'twanttostorepasswordsplaintext!const{password,...rest}=doc;consthash=awaitbcrypt.hash(password,SALT_ROUNDS);constdocToInsert=Object.assign({},rest,{hash,createdAt:Date.now(),updatedAt:Date.now(),});//Thiscodeisunchanged.constid=(awaitthis.collection.insertOne(docToInsert)).insertedId;this.pubsub.publish('userInserted',awaitthis.findOneById(id));returnid;}}ClientsidecodeTocreateusers,simplycallyourgeneratedcreateUsermutation(youmaywanttoaddauthorizationtotheresolver,feelfreetomodifyit).
Tologinontheclient,youmakeaRESTfulrequestto/loginontheserver,passingemailandpasswordinJSON.You'llgetaJWTtokenback,whichyoushouldattachtotheAuthorizationheaderofallGraphQLrequests.
Here'ssomecodetodojustthat:
constKEY='authToken';lettoken=localStorage.getItem(KEY);constnetworkInterface=createNetworkInterface(/*asusual*/);networkInterface.use([{applyMiddleware(req,next){req.options.headers={authorization:token?`JWT${token}`:null,...req.options.headers,};next();},},]);//Createyourclientasusualandpasstoaproviderconstclient=/*...*///Callthisfunctionfromyourloginform,orwherever.constlogin=asyncfunction(serverUrl,email,password){constresponse=awaitfetch(`${serverUrl}/login`,{method:'POST',body:JSON.stringify({email,password}),headers:{'Content-Type':'application/json'},});constdata=awaitresponse.json();token=data.token;localStorage.setItem(KEY,token);}DevelopmentRunningcodegenerationtestsYoucanrunsomebasiccodegenerationtestswithnpmtest.
TestingfullappcodegenerationAsimpletesttocheckthatusingthetest/inputinputfileswiththeCGSscriptsgeneratestest/output-appcanberunwithnpmrunoutput-app-generation-test.
Runningend-to-endtestsYoucanrunasetofend-to-endtestsoftheuser/tweetapp(whichlivesintest/output-app)withnpmrunend-to-end-test.Thiswillseedthedatabase,andrunagainstarunningserver.
Thetestfilesareintest/output-app-end-to-end.
Youneedtostartthestandardserverwithcdtest/output-app;npmstart,thenrunnpmrunend-to-end-test.
CreatingseeddatabaseIfyouneedtochangethefixturesforthetestdb
Starttheserver,thenrun
mongoexport--host127.0.0.1:3002--dbdatabase--collectionuser>seeds/User.jsonmongoexport--host127.0.0.1:3002--dbdatabase--collectiontweet>seeds/Tweet.jsonMaintenanceAsthisisacodegenerator,andnotalibrary,onceyourunthecode,youareonyourown:)
BywhichImean,youshouldfeelfreetoreadthegeneratedcode,understandit,andmodifyitasyouseefit.AnyupdatestoCGSwilljustaffectfutureappsthatyougenerate.
Ifyou'dliketoseeimprovements,orfindanybugs,byallmeansreportthemviatheissues,andsendPRs.Butworkaroundsshouldbealwaysbepossiblesimplybypatchingthegeneratedcode.
评论