React

数据查询语言

GraphQL

代码示例:

// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

const app = express()
// 轮廓
const Schema = buildSchema(`
    type Query {
        hello: String
    }
`)
const root = {  // 处理器
    hello: () => {
        // 模拟数据库查询
        return 'Hello World!'
    }
}

app.use('/home', (req, res) => {
    res.send('home data')
})

app.use('/list', (req, res) => {
    res.send('list data')
})

app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true  // 开启查询器
}))

app.listen(3000)

/*
query {
  hello
}
*/

参数类型与传递

代码示例:

// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

const app = express()

const Schema = buildSchema(`
    type Account {
        name: String,
        age: Int,
        location: String
    }

    type Film {
        id: Int,
        name: String,
        price: Int
    }

    type Query {
        getAllNames: [String],
        getAccountInfo: Account,
        getNowplayingList: [Film],
        getFilmDetail(id: Int!):Film
    }
`)
// !:必须传的参数

const fakeDB = [
    {
        id: 1,
        name: 'Foo',
        price: 1024
    }
]

const root = {
    getAllNames: () => {
        return ['aaa', 'bbb', 'ccc']
    },
    getAccountInfo: () => {
        // 模拟数据库
        return {
            name: 'Bar',
            age: 24,
            location: '幻想乡'
        }
    },
    getNowplayingList() {
        return fakeDB
    },
    getFilmDetail({id}) {
        // console.log(obj, id)
        return fakeDB.filter(item => item.id === id)[0]  // 因为返回的并不是一个纯数组
    }
}

app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true
}))

app.listen(3000)

/*
query {
  getAllNames,
  getAccountInfo {
    name
  },
  getNowplayingList {
    id,
    name
  },
  getFilmDetail(id: 1) {
    id
  }
}
*/

mutation

代码示例:

// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

const app = express()

const Schema = buildSchema(`
    type Film {
        id: Int,
        name: String,
        price: Int
    }

    input FilmInput {
        name: String,
        price: Int
    }

    type Query {
        getNowplayingList: [Film],
    },

    type Mutation {
        createFilm(input: FilmInput): Film,
        updateFilm(id: Int, input: FilmInput): Film,
        deleteFilm(id: Int!): Int
    }
`)

let fakeDB = [
    {
        id: 1,
        name: 'Foo',
        price: 1024
    }
]

const root = {
    getNowplayingList() {
        return fakeDB
    },
    createFilm({input}) {  // 模拟
        const obj = {...input, id: fakeDB.length + 1}
        fakeDB.push(obj)
        return obj
    },
    updateFilm({id, input}) {
        // console.log(id, input)
        let current = null
        fakeDB = fakeDB.map(item => {
            if (item.id === id) {
                current = {...item, ...input}
                return {...item, ...input}
            }
            return item
        })
        return current
    },
    deleteFilm({id}) {
        fakeDB = fakeDB.filter(item => item.id !== id)
        return 1
    }
}
app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true
}))

app.listen(3000)

/*
# query {

# }

mutation {
  # createFilm(input: {
  #   name: "Bar",
  #   price: 2048
  # }) {
  #   id,
  #   name,
  #   price
  # }

  # updateFilm(id: 1, input: {
  #   name: "HQSY"
  # }) {
  #   id
  # }

  deleteFilm(id: 1)
}
*/

结合数据库

代码示例:

// db.js

const mongoose = require('mongoose')

mongoose.connect('mongodb://127.0.0.1:27017/test')
// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

require('./db')
const mongoose = require("mongoose");

const FilmModel = mongoose.model('film', new mongoose.Schema({
    name: String,
    price: Number
}))

const app = express()

const Schema = buildSchema(`
    type Film {
        id: String,
        name: String,
        price: Int
    }

    input FilmInput {
        name: String,
        price: Int
    }

    type Query {
        getNowplayingList: [Film],
    },

    type Mutation {
        createFilm(input: FilmInput): Film,
        updateFilm(id: String, input: FilmInput): Film,
        deleteFilm(id: String!): Int
    }
`)
// id字段会自动转换_id

const root = {
    getNowplayingList() {
        return FilmModel.find()
    },
    createFilm({input}) {
        return FilmModel.create({  // 本身返回值就是Promise对象
            ...input
        })
    },
    updateFilm({id, input}) {
        return FilmModel.updateOne({
            _id: id
        }, {
            ...input
        }).then(res => FilmModel.find({_id: id})).then(res => res[0])  // 返回的对象跟之前不一样
    },
    deleteFilm({id}) {
        return FilmModel.deleteOne({_id: id}).then(res => 1).catch(err => 0)
    }
}
app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true
}))

app.listen(3000)

结合HTML

代码示例:

// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

require('./db')
const mongoose = require("mongoose");

const FilmModel = mongoose.model('film', new mongoose.Schema({
    name: String,
    price: Number
}))

const app = express()

const Schema = buildSchema(`
    type Film {
        id: String,
        name: String,
        price: Int
    }

    input FilmInput {
        name: String,
        price: Int
    }

    type Query {
        getNowplayingList: [Film],
    },

    type Mutation {
        createFilm(input: FilmInput): Film,
        updateFilm(id: String, input: FilmInput): Film,
        deleteFilm(id: String!): Int
    }
`)

const root = {
    getNowplayingList() {
        return FilmModel.find()
    },
    createFilm({input}) {
        return FilmModel.create({
            ...input
        })
    },
    updateFilm({id, input}) {
        return FilmModel.updateOne({
            _id: id
        }, {
            ...input
        }).then(res => FilmModel.find({_id: id})).then(res => res[0])
    },
    deleteFilm({id}) {
        return FilmModel.deleteOne({_id: id}).then(res => 1).catch(err => 0)
    }
}
app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true
}))

app.use(express.static('public'))

app.listen(3000)
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <button onclick="getData()">查询数据</button>
    <button onclick="createData()">创建数据</button>
    <button onclick="updateData()">更新数据</button>
    <button onclick="deleteData()">删除数据</button>
    <script>
        function getData() {
            const query = `
            query {
                getNowplayingList {
                    id,
                    name
                }
            }
            `

            fetch('/graphql', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    query
                })
            }).then(res => res.json()).then(res => {
                console.log(res)
            })
        }

        function createData() {
            const query = `
            mutation($input: FilmInput) {
                createFilm(input: $input) {
                    id,
                    name
                }
            }
            `

            fetch('/graphql', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    query,
                    variables: {  // 固定的字段
                        input: {
                            name: "Foo",
                            price: 1024,
                        }
                    }
                })
            }).then(res => res.json()).then(res => {
                console.log(res)
            })
        }

        function updateData() {
            const query = `
            mutation($id: String!, $input: FilmInput) {
                updateFilm(id: $id, input: $input) {
                    id,
                    name
                }
            }
            `

            fetch('/graphql', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    query,
                    variables: {
                        id: "6321a5a361e5cd6a24c16419",
                        input: {
                            name: "Bar",
                            price: 2048,
                        }
                    }
                })
            }).then(res => res.json()).then(res => {
                console.log(res)
            })
        }

        function deleteData() {
            const query = `
            mutation($id: String!) {
                deleteFilm(id: $id)
            }
            `

            fetch('/graphql', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                },
                body: JSON.stringify({
                    query,
                    variables: {
                        id: "6321a5a361e5cd6a24c16419"
                    }
                })
            }).then(res => res.json()).then(res => {
                console.log(res)
            })
        }
    </script>
</body>
</html>

结合React

无参数

代码示例:

// src/setupProxy.js

const {createProxyMiddleware} = require('http-proxy-middleware')

module.exports = (app) => {
    app.use(
        '/graphql',
        createProxyMiddleware({
            target: 'http://localhost:3000',
            changeOrigin: true
        })
    )
}
// src/App.jsx

import React from "react";
import {createRoot} from "react-dom/client";
import App from "./graphql/query";

createRoot(document.getElementById('root')).render(<App/>)
// src/graphql/query.jsx

import React from "react";
import {ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery} from '@apollo/client';

const client = new ApolloClient({
    uri: '/graphql',
    cache: new InMemoryCache(),
});

function MyQuery() {
    const GET_LOCATIONS = gql`
        query {
            getNowplayingList {
                id,
                name,
                price
            }
        }
    `
    const {loading, data} = useQuery(GET_LOCATIONS);
    // console.log(loading, error, data)

    return (
        <div>
            {
                !loading && data.getNowplayingList.map(item => <div key={item.id}>
                    <div>名字:{item.name}</div>
                    <div>价格:{item.price}</div>
                </div>)
            }
        </div>
    )
}

export default function App() {
    return (
        <ApolloProvider client={client}>
            <MyQuery/>
        </ApolloProvider>
    )
}

有参数

代码示例:

// helloworld.js

const express = require('express')
const {buildSchema} = require('graphql')
const {graphqlHTTP} = require('express-graphql')

require('./db')
const mongoose = require("mongoose");

const FilmModel = mongoose.model('film', new mongoose.Schema({
    name: String,
    price: Number
}))

const app = express()

const Schema = buildSchema(`
    type Film {
        id: String,
        name: String,
        price: Int
    }

    input FilmInput {
        name: String,
        price: Int
    }

    type Query {
        getNowplayingList(id: String!): [Film],
    },

    type Mutation {
        createFilm(input: FilmInput): Film,
        updateFilm(id: String!, input: FilmInput): Film,
        deleteFilm(id: String!): Int
    }
`)

const root = {
    getNowplayingList({id}) {
        return FilmModel.find({_id: id})
    },
    createFilm({input}) {
        return FilmModel.create({
            ...input
        })
    },
    updateFilm({id, input}) {
        return FilmModel.updateOne({
            _id: id,
        }, {
            ...input
        }).then(res => FilmModel.find({_id: id})).then(res => res[0])
    },
    deleteFilm({id}) {
        return FilmModel.deleteOne({_id: id}).then(res => 1).catch(err => 0)
    }
}
app.use('/graphql', graphqlHTTP({
    schema: Schema,
    rootValue: root,
    graphiql: true
}))

app.use(express.static('public'))

app.listen(3000)
// src/graphql/query.jsx

import React, {useState} from "react";
import {ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery} from '@apollo/client';

const client = new ApolloClient({
    uri: '/graphql',
    cache: new InMemoryCache(),
});

function MyQuery() {
    const [state, setState] = useState({
        id: "632187347260573c261b1a42"
    })
    const query = gql`
        query getNowplayingList($id: String!) {
            getNowplayingList(id: $id) {
                id,
                name,
                price
            }
        }
    `
    const {loading, data} = useQuery(query, {
        variables: {id: state.id}
    });
    // console.log(loading, error, data)

    return (
        <div>
            <input type="text" onChange={evt => {
                setState({
                    id: evt.target.value
                })
            }}/>
            {
                !loading && data.getNowplayingList.map(item => <div key={item.id}>
                    <div>名字:{item.name}</div>
                    <div>价格:{item.price}</div>
                </div>)
            }
        </div>
    )
}

export default function App() {
    return (
        <ApolloProvider client={client}>
            <MyQuery/>
        </ApolloProvider>
    )
}

React-mutation

代码示例:

// src/graphql/query.jsx

import React from "react";
import {ApolloClient, InMemoryCache, ApolloProvider, gql, useMutation} from '@apollo/client';

const client = new ApolloClient({
    uri: '/graphql',
    cache: new InMemoryCache(),
});

function MyQuery() {
    const query = gql`
        mutation createFilm($input: FilmInput) {
            createFilm(input: $input) {
                id,
                name,
                price
            }
        }
    `
    const [createFilm] = useMutation(query, {
        variables: {
            input: {
                name: "Foo",
                price: 1024
            }
        }
    })
    // console.log(createFilm)

    return (
        <div>
            <button onClick={() => {
                createFilm().then(res => {
                    console.log(res)
                }).catch(err => console.log(err))
            }}>add</button>
        </div>
    )
}

export default function App() {
    return (
        <ApolloProvider client={client}>
            <MyQuery/>
        </ApolloProvider>
    )
}

代码示例:

// src/graphql/query.jsx

import React from "react";
import {ApolloClient, InMemoryCache, ApolloProvider, gql, useMutation} from '@apollo/client';

const client = new ApolloClient({
    uri: '/graphql',
    cache: new InMemoryCache(),
});

function MyQuery() {
    const query = gql`
        mutation deleteFilm($id: String!) {
            deleteFilm(id: $id)
        }
    `
    const [deleteFilm] = useMutation(query, {
        variables: {
            id: "6321da8867b4e3a653f55129"
        }
    })

    return (
        <div>
            <button onClick={() => {
                deleteFilm().then(res => {
                    console.log(res)
                }).catch(err => console.log(err))
            }}>delete</button>
        </div>
    )
}

export default function App() {
    return (
        <ApolloProvider client={client}>
            <MyQuery/>
        </ApolloProvider>
    )
}

代码示例:

// src/graphql/query.jsx

import React from "react";
import {ApolloClient, InMemoryCache, ApolloProvider, gql, useMutation} from '@apollo/client';

const client = new ApolloClient({
    uri: '/graphql',
    cache: new InMemoryCache(),
});

function MyQuery() {
    const query = gql`
        mutation updateFilm($id: String!, $input: FilmInput) {
            updateFilm(id: $id, input: $input) {
                id,
                name,
                price
            }
        }
    `
    const [updateFilm] = useMutation(query, {
        variables: {
            id: "6321da8867b4e3a653f55129",
            input: {
                name: "Foo",
                price: 1024
            }
        }
    })

    return (
        <div>
            <button onClick={() => {
                updateFilm().then(res => {
                    console.log(res)
                }).catch(err => console.log(err))
            }}>update</button>
        </div>
    )
}

export default function App() {
    return (
        <ApolloProvider client={client}>
            <MyQuery/>
        </ApolloProvider>
    )
}