在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称(OpenSource Name):nicolasdao/graphql-serverless开源软件地址(OpenSource Url):https://github.com/nicolasdao/graphql-serverless开源编程语言(OpenSource Language):JavaScript 95.7%开源软件介绍(OpenSource Introduction):GraphQL For Serverless ·graphql-serverless is a middleware for webfunc, that allows to deploy GraphQL apis (including an optional GraphiQL interface) to the most popular serverless platforms. GraphQl Subscriptions over websocket are also supported out-of-the-box (also supported in GraphiQL). Without changing a single line of code, seamlessly deploy to:
Copy/paste the following in your terminal if you want to run your first GraphQL api (http://localhost:4000) including a GraphiQL interface (http://localhost:4000/graphiql) on your local machine in less than 30 seconds:
This will serve 2 endpoints:
Deploying that api to Zeit Now will take between 15 seconds to 1.5 minute (depending on whether you need to login/creating a free Zeit account or not). If you haven't installed Zeit now-CLI yet or you need to login/create an account, then copy/paste this in your terminal:
The above will work the exact same way whether you have an account or not. This is free, so don't worry about it. If you're already logged in, then simply run this:
Table Of ContentsInstall
How To Use ItBasicsUsing the template above (i.e. graphql-universal-server) is the easiest way to start a new GraphQL project from scratch. However, if you really want to start on a blank page:
const { graphqlHandler, graphqlError } = require('graphql-serverless')
const { makeExecutableSchema } = require('graphql-tools') // this dependency is automatically included in 'graphql-serverless'
const { app } = require('webfunc')
// STEP 1. Mock some data for this demo.
const productMocks = [
{ id: 1, name: 'Product A', shortDescription: 'First product.' },
{ id: 2, name: 'Product B', shortDescription: 'Second product.' }]
// STEP 2. Creating a basic GraphQl Schema.
const schema = `
type Product {
id: ID!
name: String!
shortDescription: String
}
type Query {
products(id: Int): [Product]
}
schema {
query: Query
}`
const productResolver = {
Query: {
products(root, { id }, context) {
const results = id ? productMocks.filter(p => p.id == id) : productMocks
if (results.length > 0)
return results
else
throw graphqlError(404, `Product with id ${id} does not exist.`)
}
}
}
const executableSchema = makeExecutableSchema({
typeDefs: schema,
resolvers: productResolver
})
// STEP 3. Creating a GraphQL and a GraphiQl endpoint
const graphqlOptions = {
schema: executableSchema,
graphiql: { // If you do not want to host any GraphiQl web interface, leave this property undefined.
endpoint: '/graphiql'
},
context: {
someVar: 'This variable is passed in the "context" object in each resolver.'
}
}
// Host a GraphQl API on 2 endpoints: '/' and '/graphiql'. '/graphiql' is used to host the GraphiQL web interface.
// If you're not interested in the GraphiQl web interface, leave the above 'graphqlOptions.graphiql' undefined and
// replace the path following ['/', '/graphiql'] with '/'.
app.all(['/', '/graphiql'], graphqlHandler(graphqlOptions))
// STEP 4. Starting the server
eval(app.listen('app', 4000))
This will serve 2 endpoints:
GraphQl Subscriptions
graphql-serverless exposes a helper method
Install graphql-subscriptions:
Update the previous // MODIFICATION A - Import the 'setupSubscriptions' helper
const { graphqlHandler, graphqlError, setupSubscriptions } = require('graphql-serverless')
...
// MODIFICATION B - Create a simple local pub/sub (not scalable option, but good enough for a demo)
const { PubSub } = require('graphql-subscriptions')
const pubsub = new PubSub()
...
// MODIFICATION C/D - Add an 'insert product' MUTATION and a 'product inserted' SUBSCRIPTION in the GraphQl schema
const schema = `
input NewProductInput {
name: String!
shortDescription: String
}
type Mutation {
productInsert(product: NewProductInput!): Product
}
type Subscription {
productInserted: Product
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}`
...
// MODIFICATION C/D - Add an 'insert product' MUTATION and a 'product inserted' SUBSCRIPTION in the GraphQl product resolver
const productResolver = {
Query: {...},
Mutation: {
productInsert(root, { product }, context) {
if (!product || !product.name)
throw context.graphqlError('Missing required argument \'product.name\'.')
const newId = productMocks.sort((a,b) => a.id < b.id)[0].id + 1
const newProduct = Object.assign({ id: newId }, product)
productMocks.push(newProduct)
pubsub.publish('productInserted', { productInserted: newProduct })
return newProduct
}
},
Subscription: {
productInserted: {
subscribe: () => pubsub.asyncIterator('productInserted')
}
}
}
...
// MODIFICATION A - Define the location of the subscriptions endpoint
const graphqlOptions = {
schema: executableSchema,
graphiql: {
endpoint: '/graphiql'
},
subscriptionsEndpoint: '/subscriptions' // this means that the subscription endpoint is 'ws://localhost:4000/subscriptions' if you're deploying locally
}
...
// MODIFICATION A - Start the websocket endpoint after the server as started.
// WARNING: This only works for localhost, serverless Zeit Now, but not
// for FaaS like AWS Lambdas, Google Functions, ...
eval(app.listen('app', 4000, () => setupSubscriptions(app.server, graphqlOptions))) Execute subscription {
productInserted {
id
name
}
} At that point, the client is simply listening to any new messages on the 'productInserted' topic. Time to publish a new messages on that topic. Open a new tab and browse again to http://localhost:4000/graphiql. There insert a new product as follow: mutation {
productInsert(product: {
name: "Product C"
}) {
id
name
}
} Once the product has been inserted, you should be able to observe that your subscription client has noticed it. Customizing GraphiQLThe code sample in the Basics section uses the default GraphiQl settings: By updating the const graphqlOptions = {
schema: executableSchema,
graphiql: {
endpoint: '/graphiql',
head: {
title: 'Neap GraphQl API',
// Adding a custom Favicon
custom: '<link rel="shortcut icon" href="https://neap.co/favicon.ico">',
// Change the default 'light' theme to a dark one.
theme: 'dark',
// Replace the default 'GraphiQl' logo to your own
logo: '<div class="title"><img src="https://neap.co/img/neap_white_small_logo.png" style="width: 88px;z-index: 7;padding-left: 24px;"></div>'
},
// Adding a custom JS script
script: () => {
function getCookie(cname) {
var name = cname + '='
var decodedCookie = decodeURIComponent(document.cookie)
var ca = decodedCookie.split(';')
for(var i = 0; i <ca.length; i++) {
var c = ca[i]
while (c.charAt(0) == ' ')
c = c.substring(1)
if (c.indexOf(name) == 0)
return c.substring(name.length, c.length)
}
return ''
}
},
// Executing a custom JS function each time a GraphQL request is made
onRequest: headers => {
var token = getCookie('neap_cookie')
if (token)
headers.Authorization = 'bearer ' + token
}
}
} We can update the GraphiQL interface as follow: The differences are:
To use a custom CSS rather than relying on the 'light' or 'dark' theme, you can use the const graphqlOptions = {
schema: executableSchema,
graphiql: {
endpoint: '/graphiql',
head: {
// Adding a dark theme
css: [
'https://neap.co/resources/css/graphiql/0.0.1/dark_style.css',
'https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700|Source+Code+Pro:200,400,700']
}
}
}
Managing GraphQl ErrorsBy default, any uncaught errors are marshalled to the graphql response similar to this: {
"errors": [
{
"message": "Product with id 20 does not exist.",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"products"
]
}
],
"data": {
"products": null
}
} This type of uncaught error also yield a 500 HTTP code. A piece of code that could produce the error above could be: const productResolver = {
Query: {
products(root, { id }, context) {
const results = id ? productMocks.filter(p => p.id == id) : productMocks
if (results.length > 0)
return results
else
throw new Error(`Product with id ${id} does not exist.`)
}
}
} However, there are situation where you may want to control the error being returned in one of the following ways:
This can be achieved thanks to the const { graphqlHandler, graphqlError } = require('graphql-serverless')
const productResolver = {
Query: {
products(root, { id }, context) {
const results = id ? productMocks.filter(p => p.id == id) : productMocks
if (results.length > 0)
return results
else
throw graphqlError({ code: 404, text: `Product with id ${id} does not exist.` })
}
}
} In case of errors, the response will look like this: {
"errors": [
{
"message": "Product with id 123 does not exist."
}
],
"data": {
"products": null
}
} The throw graphqlError({ code: 422, errors:[error] }) The output in case of errors is similar to: {
"errors": [
{
"message": "Some error message",
"locations": [
{
"line": 382,
"col": 17,
"method": "wrapErrors",
"path": "/Users/nicolasdao/Documents/myproject/src/services/_utils.js"
},
{
"line": 65,
"col": 19,
"method": "onFulfilled",
"path": "/Users/nicolasdao/Documents/myproject/src/services/core/node_modules/co/index.js"
}
]
}
],
"data": {
"products": null
}
} If the stack information in the throw graphqlError({ code: 422, errors:[error], noStack:true }) APIgraphqlError('Oops, the product does not exist.') Returns a GraphQL error response with the above error message and a HTTP 500. graphqlError('Oops, the product does not exist.', { alternateMessage: 'Internal Server Error', hide: true }) Returns a GraphQL error response with error message 'Internal Server Error' (if the graphqlError(404, 'Oops, the product does not exist.') Returns a GraphQL error response with the above error message and a HTTP 404. graphqlError(404, 'Oops, the product does not exist.', { alternateMessage: 'Internal Server Error', hide: true }) Returns a GraphQL error response with error message 'Internal Server Error' (if the Controling GraphQl Server Behavior With Custom MiddlewareThis section is broken down in 3 parts: OverviewAt the end, graphql-serverless is simply another Express-like middleware, and as such, we've added the ability to react differently based on other middleware that may have manipulated the request object previously. Those early middleware can affect the behavior of graphql-serverless thanks to the Let's take the 全部评论
专题导读
上一篇:hiteshchoudhary/lco-graphql: A standard babel setup发布时间:2022-06-22下一篇:SWAPI GraphQL API发布时间:2022-06-22热门推荐
热门话题
阅读排行榜
|
请发表评论