Tutorial: Transform a REST API to GraphQL
Create a GraphQL API for REST interfaces by letting API Connect for GraphQL introspect the REST endpoint and generate a GraphQL schema.
This tutorial shows how to use the stepzen import curl
command on an existing REST
API. This command sends a curl request to API Connect for GraphQL and parses the GraphQL types
from the JSON response.
Working with GET
requests
Use the API Connect for GraphQL CLI to create
a GraphQL schema for your new GraphQL API. Complete the following steps to perform this process
using our example customers
API:
Generate your schemas and resolvers using the following API Connect for GraphQL CLI command:
stepzen import curl https://introspection.apis.stepzen.com/customers --query-name "customers" --query-type "Customer" --name "customers"
Let's take a look at what the stepzen import curl
command does:
- API Connect for GraphQL issues the
curl
call (we support most, but not all,curl
flags, as explained in the following section). - It converts the returned JSON into a set of GraphQL types.
The
root
of the returned JSON was given a special name, in thisCustomerEntry
, based on thequery-type
flag. This flag is optional, but it is good to give a meaningful name for theroot
because otherwise, API Connect for GraphQL will name itRootEntry
.If you execute two different
stepzen import curl
commands, theRootEntry
will be a type name clash. Other types get fairly good names based on thename
in the JSON structure. If you are worried about type name clashes on them, you can use a--prefix
flag (more on that later). - It then generates a query with the value of the
--query-name
flag so that when you execute the query, it will parse the returned JSON into the correct GraphQL structure.While this flag is optional, it is highly recommended because otherwise, the default name would be
myQuery
, and not only is it not a great name, it will clash with any subsequentstepzen import curl
commands that you run. - It stores the generated schema in a directory with the name given in
name
flag. It is optional, and it will create a directory that starts withcurl
(for the first one, andcurl-01
etc., for each subsequentstepzen import curl
command). - It creates an
index.graphql
in the root of your working directory containing the path to which the schema file is generated.
Just one command did all this for you!
- Using
curl
with headers -
API Connect for GraphQL stores all headers in a
config.yaml
file. The followingcurl
command contains a header, so API Connect for GraphQL creates a file namedconfig.yaml
:stepzen import curl https://api.foo.com/bar -H 'Authorization: Bearer 347ack988dkey'
The
config.yaml
contains an entry for the header, which looks like the following example (there might be other entries in it as well):configurationset: - configuration: name: some-auto-generated-name Authorization: Bearer 347ack988dkey
API Connect for GraphQL also modifies the generated schema to create a query like the following example:
type Query { myQuery: RootEntry @rest( endpoint: "https://api.foo.com/bar" configuration: "some-auto-generated-name" ) }
This ensures that your secrets (typically contained in headers) are stored separately from your code (your schema file).
Even if you do not have headers but are sending an
apikey
or something else in theendpoint
, you can move it to theconfig.yaml
file. - Using
curl
with query parameters API Connect for GraphQL automatically converts all
https://api.foo.com/bar?name=anant&country=UScurl
query parameters to arguments in the GraphQL query that is generated. For example, the request:generates the following query:
type Query { myQuery(name: String!, country: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar") }
Where did the
query
arguments go? In API Connect for GraphQL, GraphQL query arguments are appended to the endpoint URL as query string parameters. The generated query has the same effect as the following query that includes the arguments, but gives you more control:type Query { myQuery(username: String!, country: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?name=$username&country=$country") }
- Preventing query parameters and arguments from being appended to the endpoint
-
You can specify rules to prevent API Connect for GraphQL from auto-appending the GraphQL query arguments and query string parameters. For example, you might want to suppress the parameters or arguments in the following situations:
- When there is already a query parameter.
For example, you can run the following command:
stepzen import curl "https://api.foo.com/bar?name=anant&country=US"`
and then edit the SDL to only allow queries on
country=US
:type Query { myQuery(name: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?country=US") }
The
name
will not automatically be added as a query parameter because the endpoint URL does not use the required format of&name=$name
type Query { myQuery(name: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?country=US&name=$name") }
- You want to suppress parameters because they might be used in
path
orheaders
.In this case, edit the
config.yaml
as shown in the following example. Add the attributestepzen.queryextensionguard
and set it totrue
, which instructs API Connect for GraphQL not to automatically append query parameters to the request.configurationset: - configuration: name: "config" stepzen.queryextensionguard: true
- When there is already a query parameter.
- Using
curl
with path parameters -
API Connect for GraphQL can automatically convert path parameters into arguments. For example,
stepzen import curl https://example.com/users/jane/posts/12 --path-params '/users/$userId/posts/$postId'
generates a query in GraphQL like the following example:
type Query { myQuery(userId: String!, postId: Int!): RootEntry @rest(endpoint: "https://example.com/users/$userId/posts/$postId") }
- Adding arguments to the generated schema
-
The
@rest
directive that is generated fromstepzen import curl
can be customized with additional arguments to help you shape the REST response to the requested GraphQL type:transforms
to modify the responsefilter
to filter the outputsetters
andresultroot
to change names of fields, and so on.
For more information on the configuration options, see "Shaping the HTTP response" in Connecting a REST service.
Working with POST
requests
When using stepzen import curl
for a POST
request, parameter
substitution gets applied to the body of your request.
- Treating all fields in the
POST
body as query arguments -
Consider a simple case:
stepzen import curl 'http://dummy.restapiexample.com/api/v1/create' -d '{"key1":"value1", "key2":"value2"}' -H 'Content-Type: application/json'
The
curl
request uses a default header that contains-d
(or--data-raw
) isContent-Type: application/x-www-form-urlencoded
.Because GraphQL APIs rely on JSON, you must append the header
-H 'Content-Type: application/json'
to use JSON in your post body.The example
stepzen import curl
command generates a query in GraphQL like this:type Query { myQuery(key1: String, key2: String): RootEntry @rest( method: POST endpoint: "http://dummy.restapiexample.com/api/v1/create" ) }
The argument
method
with the valuePOST
is included in the@rest
directive.The JSON keys from the body are transformed into query arguments.
- Generating a mutation from a POST request
When using
stepzen import curl
, the default GraphQL operation type isQuery
. To change the import into aMutation
, manually update the schema. For example, modify the following schema:
by changing thetype Query { myQuery(key1: String, key2: String): RootEntry @rest( method: POST endpoint: "http://dummy.restapiexample.com/api/v1/create" ) }
Query
type to aMutation
type:type Mutation { myQuery(key1: String, key2: String): RootEntry @rest( method: POST endpoint: "http://dummy.restapiexample.com/api/v1/create" ) }
The
stepzen import curl
forPOST
does not handle more complicated parameter substitutions. For an overview of all the configuration options, see "Setting the HTTP request body" in Connecting a REST Service.
Best practices
- Working with multiple
curl
requests - You can issue as many
curl
requests as you want. As a matter of best practice, use the following parameters to ensure that each request uses unique values:- Use
--name
to specify a unique directories for each importedcurl
request. - Use
--query-name
to assign unique names to the queries so that you avoid query name clashes. - Use
--query-type
to give theRoot
unique names to avoid root name clashes. - Use
--prefix
to prefix all non-root types.For example,
--prefix Cust
makes all types have aCust
prefix, and this avoids type conflicts with other schemas.
- Use
Undo a stepzen import curl
command
To a stepzen import curl
command, you should:
- Delete the generated directory.
The directory has the name you specified with
--name
flag, or withcurl
orcurl-xx
. - Edit the
index.graphql
file in the root of your working directory, and remove the entry for the directory that you deleted in step 1.
That's it. Then run your stepzen import curl
command again.