Using Wazi Analyze APIs
With Wazi Analyze APIs, you can access impact analysis results in the Wazi Analyze server without the web user interface.
Getting started with Wazi Analyze APIs
All Wazi Analyze APIs are implemented in GraphQL and respond to the POST requests according to the GraphQL query protocol. A Wazi Analyze API is an integration layer for the Wazi Analyze server data provider and requires Wazi Analyze services to be running to provide data.
- Configure the host container. The Wazi Analyze host container should have an additional port mapping that is defined for accessing the APIs. The port by default in the container image is set to
4680
. When you start the Wazi Analyze container, run the following command to add the port mapping parameter.-p <host port>:4680
Note: Replace<host port>
with your preferred port to map to, for example,-p 4680:4680
- Start up and configure the servers.
The Wazi Analyze servers (
wa-startup.sh
) should be running for the API servers to be able to query the data. Starting up the Wazi Analyze servers will automatically start the Wazi Analyze API server. - Authentication and authorization.
Authentication and authorization are required for the most of the Wazi Analyze APIs, except for the introspection API described in a later section. The API user has to supply an authenticated session cookie and a pseudo bearer token when invoking the API.
The authenticated session cookie can be obtained by sending a POST request to the API/login
endpoint. The content of the request body must contain a JSON object with a single password field set to the Wazi Analyze user password. (The Wazi Analyze user password is established by passing it to the Wazi Analyze start up scriptwa-startup.sh
, either on the script command line invocation or by entering it at the script's prompt). Here is an example of the/login
POST:https://localhost:4680/login Content-Type: application/json body {"password": "sup3rC00l"}
Replace
userPassw0rd
with the password that you provided during starting up the Wazi Analyze server on Step 2.Note: The password is not stored by the Wazi Analyze API and is only used once to authenticate the login request. You can use any HTTP client, such as cURL to invoke the/login
request. For example, using cURL:curl -X POST -k -v -H "Content-Type: application/json" -d "{\"password\": \"userPassw0rd\"}" https://localhost:4680/login
Note that the
-k
cURL switch allows to bypass strict SSL/TLS certificate validation. If you have a valid SSL/TLS certificate installed on your server you should omit this switch.If the login call is successful (HTTP code 200), it will return a session cookie that is similar to the following example:
Set-Cookie: gql_session_id=s%3AtAELFpM6o6n3QFEJAe8YFELbgeo-El-n.GIcHUXJ%2FDSm0x1iDBWIN52bGN7e0gV6%2Bl2Kmatd%2BPGs; Path=/; Expires=Sat, 25 Sep 2021 04:40:09 GMT; HttpOnly; Secure; SameSite=None
The bearer token is generated when running the Wazi Analyze start up script
wa-startup.sh
and represents the password that is specified during the startup, concatenated with itself. For example, if your password isuserPassw0rd
, the bearer token will beuserPassw0rduserPassw0rd
.Most calls to the Wazi Analyze API require the bearer token as part of the Authorization header on the HTTP POST request as follows:Authorization: bearer <token>
The token value is not stored by the API component and each time you start Wazi Analyze servers, the token is reset to the new value that you provide, along with the Wazi Analyze UI password. The password can contain any combination of 5 to 15 alphanumeric characters and special symbols except equal sign =, hyphen -, or blank .
After you obtain the session cookie and the bearer token, you can use any HTTP client, such as cURL to invoke the Wazi Analyze API. For example, using cURL:
curl -k -X POST -H "Content-Type: application/json" -H "Authorization: bearer sup3rC00lsup3rC00l" -H "Cookie: gql_session_id=s%3AtAELFpM6o6n3QFEJAe8YFELbgeo-El-n.GIcHUXJ%2FDSm0x1iDBWIN52bGN7e0gV6%2Bl2Kmatd%2BPGs; Path=/; Expires=Sat, 25 Sep 2021 04:40:09 GMT; HttpOnly; Secure; SameSite=None" -d "{\"query\":\"query{projects {id type}}\"}" https://localhost:4680/azn-graphql/v1
Note that schema introspection queries (the information about the model) does not require a token.
- Access the API endpoint to view impact analysis results.Wazi Analyze API endpoint in the container is running on port
4680
as follows.https://localhost:4680/azn-graphql/v1
- Shut down the API server.
Run the
wa-shutdown.sh
script to shut down the Wazi Analyze API server, which will shut down all the Wazi Analyze servers.
API Specification
You can run queries programmatically through either command line tools, such as cURL, or a browser-based REST client, such as Postman.
GraphQL is introspective. You can query a GraphQL schema for information about what queries it supports. No authentication is required when you query a GraphQL schema.
__schema
to
list all types that are defined in the schema. query {
__schema {
types {
name
kind
description
fields {
name
}
}
}
}
curl -X POST -H "Content-Type: application/json" -d '{"query":"query{__schema {types {name kind description fields {name}}}}"}' -k https://localhost:4680/azn-graphql/v1
-k
cURL switch allows to bypass strict SSL/TLS certificate validation. If you have a valid SSL/TLS
certificate installed on your server, you should omit this switch.curl -X POST -H "Content-Type: application/json" -d "{\"query\":\"query{projects {id type}}\"}" -k https://localhost:4680/azn-graphql/v1
_type
to get
details about any type.query {
__type(name: "AznProject") {
name
kind
description
fields {
name
}
}
}
The following queries supported by
graphQL accept the following two special parameters: uid/ProjectUid
and
projectType
.
projectType
parameter supplied to the queries is to assist graphQL in
recognizing which data provider to call upon, given a specific projectId
. The
projectType
parameter accepts the following values: projectType {
'WaziAnalyze'
'ApplicationDiscovery'
}
In the case that a projectType
parameter is not specified in the
queries, graphQL will default the value to WaziAnalyze
.
Potential consumers
may not want to keep track of both the projectId
and the
projectType
of the projects returned from graphQL. In cases like these, graphQL will return
a uid
for each project that is returned when the projects query is called, and this
uid
can be used when calling other queries as uid for the project query or
projectUid
for the other queries.
Both the uid/projectUid
and
projectType
parameters are to assist graphQL to recognize the distinction between
the projects and call upon the correct data provider.
Available APIs
projects(queryString: ID): [AznBasicProject]
project(id: ID, uid: ID, projectType: String, status: Boolean): AznBasicProject
project(id: ID, uid: ID, projectType: String, status: Boolean): AznBasicProject
id: ID
type: String
label: String
metadata: JSON
//Retrieve a list of all project ids and types
POST `https://localhost:4680/azn-graphql/v1`
Authorization: bearer 0123456789
{"query": "{ projects {id type}}" }
curl -X POST -H "Authorization: bearer 0123456789" -H "Content-Type: application/json" -d '{"query":"query{projects {id type}}"}' -k https://localhost:4680/azn-graphql/v1
{
"data": {
"projects": [
{
"id": "GenAppC",
"type": "project"
},
{
"id": "GenApp_dev",
"type": "project"
},
{
"id": "GenApp_wrk",
"type": "project"
}
]
}
}
}
//Retrieve a list of project ids and metadata for all projects whose Id contains a string `wrk`
POST `https://localhost:4680/azn-graphql/v1`
Authorization: bearer 0123456789
{"query": "{ projects(queryString:\"wrk\") {id metadata}}" }
Response:
{
"data": {
"projects": [
{
"id": "GenApp_wrk",
"metadata": {
"metatype": "logical",
"info": [
"GenApp_wrk",
"2021-05-20T02:03:24",
"18",
"94",
"IMPACT"
]
}
}
]
}
}
programs(queryString: String, projectId: ID, projectUid: ID, projectType: String): [AznProgram]
//Retrieve a list of program names (labels) for all programs whose nane contains a string `LGTEST` in project `GenAppC`
{
programs(projectId: "GenAppC", queryString: "LGTEST") {
label
}
}
{
"data": {
"programs": [
{
"label": "LGTESTC1"
},
{
"label": "LGTESTP1"
},
{
"label": "LGTESTP2"
},
{
"label": "LGTESTP3"
},
{
"label": "LGTESTP4"
}
]
}
}
files(queryString: String, projectId: ID, projectUid: ID, projectType: String): [AznFile]
//Retrieve a list of file names (labels) for all files whose name contains a string `LGC` in project `GenAppC`
{
files(projectId: "GenAppC", queryString: "LGC") {
label
}
}
{
"data": {
"files": [
{
"label": "LGCMAREA.CPY"
},
{
"label": "LGCMARER.CPY"
}
]
}
}
jobs(queryString: String, projectId: ID, projectUid: ID, projectType: String): [AznJob]
//Retrieve a list of job names (labels) for all jobs whose name contains a string `DMHJCL0` in project `GenAppC`
{
jobs(projectId: "GenAppC", queryString: "DMHJCL0") {
label
}
}
{
"data": {
"jobs": [
{
"id": "DMHJCL02"
},
{
"id": "DMHJCL05"
},
{
"id": "DMHJCL07"
},
{
"id": "DMHJCL09"
}
]
}
}
The Graph API retrieves the information about the types and relationships between and among generic (as defined by a provider) program objects and/or generic file objects. The Graph response format is based on JSON Graph Format specification (V2).
graphs (
programName: String
fileName: String
jobName: String
projectId: ID
callDepth: BigInt
projectUid: ID
projectType: String
): [Graph]
The provider for Wazi Analyze data is for static source code analysis.
Based on the static analysis of code, the relationship between programs is
programCall
-type, the relationship between files is contain
-type,
the relationship between a z/OS is job
-type and its steps are
jobContain
-type. When you specify the programName
query parameter
without callDepth
, the relationship edges array in the response will contain both
the programCall
-type relationship for the specified program name and the
contain
type relationships for the files related to the program, such as included
source files. Note that if you have duplicate program names in your project, where the duplicate
program name is located in a file that has a name different from the program name, the query results
will be undetermined. Also note that the File artifacts are called modules
in the
nodes map metadata. Contain
-type (including jobContain
)
relationships do not have a depth specification and for programName
queries, the
entire set of related files will be returned, including files whose references are nested in the
relationship chain.
When you specify the programName
query parameter with
callDepth
, the relationship edges will contain only
programCall
-type relationship for the specified program name. Call depth
specification is honored in both call directions. That is, both parents and children of the program
are returned at the specified depth. Note that the nodes map may still contain File (metadata type
module
) artifacts that could be ignored for the purpose of
programCall
-type depth relationships.
When you specify the
fileName
, a contain
-type list of edges will be returned for the
fileName
. Only files that are directly referenced by the file containing the
fileName
are returned. For example, if file A
contains references
to file B
and C
, and file B
contains references
to file D
, only relationships to B
and C
will be
returned for file A
. The edges might also contain programCall
-type
relationship, and the nodes map might contain program
-type nodes, which can be
ignored for the purpose of contain
-type relationships.
When you specify
jobName
, a jobContain
-type list of edges will be returned for the
jobName
. The nodes in the job graph represent the job steps in the source
JCL.
When you specify a combination of programName
,
fileName
, or jobName
, the corresponding separate independent graph
objects will be returned. The callDepth
parameter will be applied to
programName
-based graph only.
//Retrieve graph for program with name `LGACUS01` and file `LGACUS01.CBL` in project `GenAppC`
{
graphs(projectId: "GenAppC", programName: "LGACUS01", fileName: "LGACUS01.CBL") {
id
nodes
edges {
source
target
relation
}
}
}
{
"data": {
"graphs": [
{
"id": "RAAJCL-Y2KMVSBD-jobgraph",
"type": "Jobs",
"label": "Hypercube data extract: column=job%2Bjobstep%2Bexttype%2Bextref%2Bextvalue%2Bdisposition",
"nodes": {
"job:Y2KMVSBD": {
"label": "Y2KMVSBD",
"metadata": {
"type": "job"
}
},
"jobstep:1:LKED": {
"label": "LKED",
"metadata": {
"type": "jobstep",
"stepnum": 1,
"exttype": "EXEC",
"extref": "IEWL",
"extvalue": "(LET,MAP,LIST)",
"disposition": "",
"ref": [
{
"id": "ref:SYSLIB:1:LKED",
"exttype": "DD",
"extref": "SYSLIB",
"extvalue": "LE370.V1R5M0.SCEELKED",
"disposition": "SHR"
},
{
"id": "ref:SYSLIB:1:LKED",
"exttype": "DD",
"extref": "SYSLIB",
"extvalue": "DB2.V5R1M0.SDSNLOAD",
"disposition": "SHR"
},
{
"id": "ref:SYSPRINT:1:LKED",
"exttype": "DD",
"extref": "SYSPRINT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSLMOD:1:LKED",
"exttype": "DD",
"extref": "SYSLMOD",
"extvalue": "LSTAUS.QA.LOADLIB",
"disposition": "SHR"
},
{
"id": "ref:SYSUT1:1:LKED",
"exttype": "DD",
"extref": "SYSUT1",
"extvalue": "UNIT",
"disposition": ""
},
{
"id": "ref:OBJECT:1:LKED",
"exttype": "DD",
"extref": "OBJECT",
"extvalue": "LSTAUS.QA.OBJ",
"disposition": "OLD"
},
{
"id": "ref:SYSLIN:1:LKED",
"exttype": "DD",
"extref": "SYSLIN",
"extvalue": "",
"disposition": ""
},
{
"id": "ref:SYSLIB:1:LKED",
"exttype": "DD",
"extref": "SYSLIB",
"extvalue": "CICS.V4R1M0.SDFHLOAD",
"disposition": "SHR"
},
{
"id": "ref:SYSLMOD:1:LKED",
"exttype": "DD",
"extref": "SYSLMOD",
"extvalue": "LSTAUS.QA.CICS.LOADLIB",
"disposition": "SHR"
}
]
}
},
"jobstep:1:LKED:EXEC:IEWL": {
"label": "IEWL",
"metadata": {
"type": "EXEC",
"stepnum": 1
}
},
"jobstep:2:BIND": {
"label": "BIND",
"metadata": {
"type": "jobstep",
"stepnum": 2,
"exttype": "EXEC",
"extref": "IKJEFT1A",
"extvalue": "",
"disposition": "",
"ref": [
{
"id": "ref:STEPLIB:2:BIND",
"exttype": "DD",
"extref": "STEPLIB",
"extvalue": "DB2.V5R1M0.SDSNEXIT",
"disposition": "SHR"
},
{
"id": "ref:STEPLIB:2:BIND",
"exttype": "DD",
"extref": "STEPLIB",
"extvalue": "DB2.V5R1M0.SDSNLOAD",
"disposition": "SHR"
},
{
"id": "ref:DBRMLIB:2:BIND",
"exttype": "DD",
"extref": "DBRMLIB",
"extvalue": "LSTAUS.QA.DBRMLIB",
"disposition": "SHR"
},
{
"id": "ref:SYSPRINT:2:BIND",
"exttype": "DD",
"extref": "SYSPRINT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSTSPRT:2:BIND",
"exttype": "DD",
"extref": "SYSTSPRT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSUDUMP:2:BIND",
"exttype": "DD",
"extref": "SYSUDUMP",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSTSIN:2:BIND",
"exttype": "DD",
"extref": "SYSTSIN",
"extvalue": "",
"disposition": ""
}
]
}
},
"jobstep:2:BIND:EXEC:IKJEFT1A": {
"label": "IKJEFT1A",
"metadata": {
"type": "EXEC",
"stepnum": 2
}
},
"jobstep:3:DATEFILE": {
"label": "DATEFILE",
"metadata": {
"type": "jobstep",
"stepnum": 3,
"exttype": "EXEC",
"extref": "IDCAMS",
"extvalue": "",
"disposition": "",
"ref": [
{
"id": "ref:SYSPRINT:3:DATEFILE",
"exttype": "DD",
"extref": "SYSPRINT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSIN:3:DATEFILE",
"exttype": "DD",
"extref": "SYSIN",
"extvalue": "",
"disposition": ""
}
]
}
},
"jobstep:3:DATEFILE:EXEC:IDCAMS": {
"label": "IDCAMS",
"metadata": {
"type": "EXEC",
"stepnum": 3
}
},
"jobstep:4:MKDATEFL": {
"label": "MKDATEFL",
"metadata": {
"type": "jobstep",
"stepnum": 4,
"exttype": "EXEC",
"extref": "ICEMAN",
"extvalue": "",
"disposition": "",
"ref": [
{
"id": "ref:SYSOUT:4:MKDATEFL",
"exttype": "DD",
"extref": "SYSOUT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:SYSPRINT:4:MKDATEFL",
"exttype": "DD",
"extref": "SYSPRINT",
"extvalue": "",
"disposition": ""
},
{
"id": "ref:SORTIN:4:MKDATEFL",
"exttype": "DD",
"extref": "SORTIN",
"extvalue": "",
"disposition": ""
},
{
"id": "ref:SORTOUT:4:MKDATEFL",
"exttype": "DD",
"extref": "SORTOUT",
"extvalue": "&DATE",
"disposition": "(NEW,PASS,DELETE)"
},
{
"id": "ref:SYSIN:4:MKDATEFL",
"exttype": "DD",
"extref": "SYSIN",
"extvalue": "",
"disposition": ""
}
]
}
},
"jobstep:4:MKDATEFL:EXEC:ICEMAN": {
"label": "ICEMAN",
"metadata": {
"type": "EXEC",
"stepnum": 4
}
},
"jobstep:5:DATELOAD": {
"label": "DATELOAD",
"metadata": {
"type": "jobstep",
"stepnum": 5,
"exttype": "EXEC",
"extref": "IDCAMS",
"extvalue": "",
"disposition": "",
"ref": [
{
"id": "ref:SYSPRINT:5:DATELOAD",
"exttype": "DD",
"extref": "SYSPRINT",
"extvalue": "SYSOUT",
"disposition": ""
},
{
"id": "ref:INDD:5:DATELOAD",
"exttype": "DD",
"extref": "INDD",
"extvalue": "&DATE",
"disposition": "(MOD,DELETE,DELETE)"
},
{
"id": "ref:OUTDD:5:DATELOAD",
"exttype": "DD",
"extref": "OUTDD",
"extvalue": "LSTAUS.QA.VSAM.CICS.DATE",
"disposition": "SHR"
},
{
"id": "ref:SYSIN:5:DATELOAD",
"exttype": "DD",
"extref": "SYSIN",
"extvalue": "",
"disposition": ""
}
]
}
},
"jobstep:5:DATELOAD:EXEC:IDCAMS": {
"label": "IDCAMS",
"metadata": {
"type": "EXEC",
"stepnum": 5
}
}
},
"edges": [
{
"target": "jobstep:1:LKED",
"source": "job:Y2KMVSBD",
"relation": "jobContain"
},
{
"target": "jobstep:1:LKED:EXEC:IEWL",
"source": "jobstep:1:LKED",
"relation": "jobExec"
},
{
"target": "jobstep:2:BIND",
"source": "job:Y2KMVSBD",
"relation": "jobContain"
},
{
"target": "jobstep:2:BIND:EXEC:IKJEFT1A",
"source": "jobstep:2:BIND",
"relation": "jobExec"
},
{
"target": "jobstep:3:DATEFILE",
"source": "job:Y2KMVSBD",
"relation": "jobContain"
},
{
"target": "jobstep:3:DATEFILE:EXEC:IDCAMS",
"source": "jobstep:3:DATEFILE",
"relation": "jobExec"
},
{
"target": "jobstep:4:MKDATEFL",
"source": "job:Y2KMVSBD",
"relation": "jobContain"
},
{
"target": "jobstep:4:MKDATEFL:EXEC:ICEMAN",
"source": "jobstep:4:MKDATEFL",
"relation": "jobExec"
},
{
"target": "jobstep:5:DATELOAD",
"source": "job:Y2KMVSBD",
"relation": "jobContain"
},
{
"target": "jobstep:5:DATELOAD:EXEC:IDCAMS",
"source": "jobstep:5:DATELOAD",
"relation": "jobExec"
}
]
}
]
}
}
javaGraph (
packageName: String
className: String
methodName: String
projectId: ID
callDepth: BigInt
projectUid: ID
projectType: String
): [Graph]
//Retrieve graph for package with name `com.ibm.db.conversion`, class `VerifyMigration`, method `main` in project `SampleJava`
{
javaGraph (projectId:"SampleJava" packageName:"com.ibm.db.conversion"
methodName:"main" className:"VerifyMigration") {
id
type
label
nodes
edges {
source
target
relation
}
}
}
{
"data": {
"javaGraph": {
"id": "SampleJava",
"type": "Java Artifacts",
"label": "Hypercube data extract for: package=com.ibm.db.conversion class=VerifyMigration method=main direction=3",
"nodes": {
"com.ibm.db.conversion::VerifyMigration::createDB2zConnection Connection(java.lang.String)": {
"label": "createDB2zConnection",
"metadata": {
"type": "method",
"package": "com.ibm.db.conversion",
"class": "VerifyMigration",
"signature": "Connection(java.lang.String)"
}
},
"com.ibm.db.conversion::VerifyMigration::main void(java.lang.String[])": {
"label": "main",
"metadata": {
"type": "method",
"package": "com.ibm.db.conversion",
"class": "VerifyMigration",
"signature": "void(java.lang.String[])"
}
},
"java.io::PrintStream::println void(java.lang.String)": {
"label": "println",
"metadata": {
"type": "method",
"package": "java.io",
"class": "PrintStream",
"signature": "void(java.lang.String)"
}
}
},
"edges": [
{
"source": "com.ibm.db.conversion::VerifyMigration::main void(java.lang.String[])",
"target": "java.io::PrintStream::println void(java.lang.String)",
"relation": "MethodCall"
},
{
"source": "com.ibm.db.conversion::VerifyMigration::main void(java.lang.String[])",
"target": "com.ibm.db.conversion::VerifyMigration::createDB2zConnection Connection(java.lang.String)",
"relation": "MethodCall"
}
]
}
}
}
authorizeProvider(
providerType: String
username: String
password: String
client_id: String
client_secret: String
grant_type: String
scope: String
): AznAuthTokenType
Note that username
, password
,
client_id
and client_secret
are required parameters.
client_id
and client_secret
are provided in the AD authorization
settings. username
and password
are the authorized user and
password for the corresponding AD accounts. For more information about AD security configuration,
see AD authentication server
documentation.mutation {authorizeProvider (providerType:"APPLICATION_DISCOVERY_SERVER"
username:"me@example.com" password:"Sup3rC!00l"
client_secret:"password") {
access_token
token_type
expires_in
refresh_token
id_token
}
}
{"query": "mutation { authorizeProvider (providerType: \"APPLICATION_DISCOVERY_SERVER\" username:\"me@example.com\" password:\"Sup3rC!00l\" client_secret:\"password\") {access_token token_type expires_in refresh_token id_token}}" };
{
"data": {
"authorizeProvider": {
"access_token": "i4323zzvmaeazb4vovmsghfmi",
"token_type": "bearer",
"expires_in": 86399,
"refresh_token": "ChlkNm9mZWtmNjJhZTQ3dnY0Z2Q1eGtqb2NhEhl2eTN1ZWtvamd5eHhjNXp5M3czYXl6b2tq",
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjViM2..."
}
}
}
Error handling
GraphQL
queries report data errors and data authorization errors through a
response body in an HTTP code 200 response. This behavior is different
from many REST-based systems where the data and authorization errors
might cause HTTP error response codes. GraphQL systems will produce
HTTP error responses in cases of network server, endpoint access errors,
and query syntax errors. Queries that result in empty responses or
other recoverable back end errors, the GraphQL-based API will return
HTTP 200 and either empty responses or a body with a standard GraphQL errors
array
content that contains the error message.
For individual query authorization errors, API will return an HTTP 200 with an errors array in the message body, for example:
{
"errors":[
{
"message": "Authorization failed. Token is not authorized.",
"locations":[
{"line": 1, "column": 2}
],
"path":[
"graph"
]
}
],
"data":{
graph": null
}
}