There are two ways to create your GraphQL API with StepZen when you have a REST backend.
- Use the command-line interface (CLI) command
stepzen import curl
to specify an existing REST endpoint - StepZen introspects the endpoint and auto-generates a GraphQL schema for you. - Write your schema code in a
.graphql
GraphQL Schema Definition Language (SDL) file. Use the powerful GraphQL directive @rest to connect the REST endpoint, and with just a few lines of code, you have a working schema.) See How to Connect a REST Service for how to write your GraphQL schema using @rest.
This topic shows how to use stepzen import curl
on an existing REST API. This command sends a curl request to StepZen and parses the GraphQL types from the JSON response.
Before you begin
Install and set up your StepZen account and the CLI.
We use stepzen import curl
in this section - you can get help for the command using stepzen import curl --help
.
GET
requests
Use the StepZen CLI to create a GraphQL schema for your new GraphQL API. Follow the steps below to perform this process using our example customers
API:
- Auto-generate your schemas and resolvers using the following StepZen CLI command:
stepzen import curl https://introspection.apis.stepzen.com/customers --query-name "customers" --query-type "Customer" --name "customers"
- Run
stepzen start
to upload and deploy your introspected schema.
Let's take a look at what the stepzen import curl
command does:
-
StepZen issues the
curl
call (we support most, but not all,curl
flags, more below). -
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, StepZen will name itRootEntry
.Furthermore, if you do two different
stepzen import curl
, 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 it 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.
So one command did all this for you!
curl
with headers
StepZen stores all headers in a config.yaml
file. So the following command
stepzen import curl https://api.foo.com/bar -H 'Authorization: Bearer 347ack988dkey'
creates a new file config.yaml
that has an entry like this:
configurationset: - configuration: name: some-auto-generated-name Authorization: Bearer 347ack988dkey
(there might be other entries in it too).
It also modifies the generated schema to create a query like:
type Query { myQuery: RootEntry @rest( endpoint: "https://api.foo.com/bar" configuration: "some-auto-generated-name" ) }
This way, your secrets (typically in headers) are stashed away separately from your code (your schema (SDL) file).
Even if you do not have headers but are sending an apikey
or something else in the endpoint
, you can move it away to config.yaml
.
curl
with query parameters
StepZen automatically converts all curl
query parameters to arguments in the GraphQL query that gets generated.
For example, https://api.foo.com/bar?name=anant&country=US
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 StepZen, we have a default behavior of appending all GraphQL query arguments to the endpoint URL as query string parameters. So in effect this the same as:
type Query { myQuery(name: String!, country: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?name=$name&country=$country") }
In this form, you get more control. So for example, you can say things like:
type Query { myQuery(username: String!, country: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?name=$username&country=$country") }
When you don't want the GraphQL query arguments automatically appended to the URL
You can specify rules to prevent StepZen from auto-appending the GraphQL query arguments and query string parameters - for example, when the URL already has a query string, or when you want to use the arguments somewhere else than URL query string (e.g. in pathname
or headers
).
- When there is already a query parameter. For example, you might do a
stepzen import curl "https://api.foo.com/bar?name=anant&country=US"
and edit the SDL to be (i.e. only allow for queries on country=US
):
type Query { myQuery(name: String!): RootEntry @rest(endpoint: "https://api.foo.com/bar?country=US") }
and you might think that name
will get added as a query parameter, but it will not. In this case, your SDL needs to be:
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 that case, add an extra line to your
config.yaml
. It sets the attributestepzen.queryextensionguard
totrue
, which instructs StepZen not to automatically append query parameters to the request by setting. An example of that file follows:
configurationset: - configuration: name: "config" stepzen.queryextensionguard: true
curl
with path parameters
StepZen can automatically convert path parameters into arguments.
stepzen import curl https://example.com/users/jane/posts/12 --path-params '/users/$userId/posts/$postId'
generates a query in GraphQL like this:
type Query { myQuery(userId: String!, postId: Int!): RootEntry @rest(endpoint: "https://example.com/users/$userId/posts/$postId") }
Customizing the autogenerated schema
The @rest
that is generated from stepzen import curl
can be customized to add
transforms
(to modify the response),filter
(to filter the output),setters
andresultroot
to change names of fields etc.
For a full overview of all the configuration options, see Using POST with REST.
POST
requests
When using stepzen import curl
for a POST
request, parameter substitution gets applied to the body of your request.
Making all fields in POST
body as query arguments
This is the simplest case:
stepzen import curl 'http://dummy.restapiexample.com/api/v1/create' -d '{"key1":"value1", "key2":"value2"}' -H 'Content-Type: application/json'
- The default header of a curl request that contains
-d
(or--data-raw
) isContent-Type: application/x-www-form-urlencoded
. - As GraphQL APIs rely on JSON, you must append the header
-H 'Content-Type: application/json'
to use JSON in your post body.
The stepzen import curl
command above 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
has been added to 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 is Query
. To change the above import into a Mutation
manually update the schema:
type Mutation { myQuery(key1: String, key2: String): RootEntry @rest( method: POST endpoint: "http://dummy.restapiexample.com/api/v1/create" ) }
Handling more complex parameter substitutions
Today stepzen import curl
for POST
does not handle more complicated parameter substitutions. For an overview of all the configuration options, see Using POST with REST.
Best practices
Working with multiple curl requrests
You can issue as many curl requests as you want. As a matter of best practice, use:
-
--query-name
gives unique names to the queries to avoid query name clashes. -
--query-type
gives theRoot
unique names to avoid root name clashes. -
--prefix
to prefix all non-root types. So for example,--prefix Cust
makes all types have aCust
prefix, and this avoids type conflicts. -
--name
to keep the directories for each imported curl different.
Undoing something
You will likely make some mistakes. To undo something that did not work as you intended (you gave the wrong path variables, you forgot to give a prefix or a query name, or whatever), you should:
- Delete the generated directory because of
stepzen import curl
. It would have the name you gave in--name
flag, orcurl
orcurl-xx
. - Edit the
index.graphql
in the root of your working directory, and remove the entry for that file (e.g.,curl/index.graphql
).
That's it. Then try your stepzen import curl
again.
Learn More
Congratulations! You've created a GraphQL API based on a REST API that includes queries, parameters, and mutations.
To extend your schema or start from scratch to write your schema code yourself, you can use the GraphQL declarative construct @rest. See How to Connect a REST Service.