Apply a change

Apply a change to the system. This is one of the most important endpoints as it centralizes every change the user can apply to the system.

Important. The API specifies a set of basic changes applicable to all dialect analized. However, this list can be extended to support more changes and refactorings by means of /extensions endpoint.

Special attention must be paid to the way the target system implementing the API must handle compilation errors so Webside ID can react properly (see Errors below).

URL: /changes

Method: POST

Payload: The payload will contain the change to be applied in JSON format. The table below lists all supported changes at this moment. Though types are self-descripted, a short description of what they do is included. All changes should include author proprerty and might specify a package property indicating the package in which the change should be applied (for example, the package that will contain a new class).

TypeDescriptionPayload

AddMethod

Compile a method in a given class.

{
 "type": "AddMethod",
 "package": "string",
 "className": "string",
 "category": "string",
 "sourceCode": "string"
} 

RemoveMethod

Remove a given method.

{
 "type": "RemoveMethod",
 "className": "string",
 "selector": "string"
} 

ClassifyMethod

Classify a given method under a given category.

{
 "type": "ClassifyMethod",
 "className": "string",
 "selector": "string",
 "category": "string"
} 

RenameMethod

Rename a given selector. The scope is the whole system.

{
 "type": "RenameMethod",
 "className": "string",
 "selector": "string",
 "newSelector": "string"
} 

AddClass

Define a new class or change the definition of an existing one.

{
 "type": "AddClass",
 "className": "string",
 "package": "string",
 "definition": "string" ,
 "instanceVariables": ["string"],
 "classVariables": ["string"],
 "poolDictionaries": ["string"]
} 

CommentClass

Change the comment of a given class.

{
 "type": "CommentClass",
 "className": "string",
 "comment": "string"
} 

RemoveClass

Remove a given class.

{
 "type": "RemoveClass",
 "className": "string"
} 

RenameClass

Rename a given class.

{
 "type": "RenameClass",
 "className": "string",
 "newName": "string",
 "renameReferences": "boolean"
} 

AddClassCategory

Rename a class category.

{
 "type": "AddClassCategory",
 "package": "string",
 "category": "string"
} 

RenameClassCategory

Rename a class category.

{
 "type": "RenameClassCategory",
 "package": "string",
 "category": "string",
 "newName": "string"
} 

RemoveClassCategory

Remove a class category.

{
 "type": "RemoveClassCategory",
 "package": "string",
 "category": "string"
} 

AddInstanceVariable

Add a new instance variable to a given class.

{
 "type": "AddInstanceVariable",
 "package": "string",
 "variable": "string"
} 

RemoveInstanceVariable

Remove an instance variable from a given class.

{
 "type": "RemoveInstanceVariable",
 "className": "string",
 "variable": "string"
} 

RenameInstanceVariable

Rename an instance variable of a given class.

{
 "type": "RenameInstanceVariable",
 "className": "string",
 "variable": "string",
 "newName": "string"
} 

MoveUpInstanceVariable

Move an instance variable from a given class to its superclass.

{
 "type": "MoveUpInstanceVariable",
 "className": "string",
 "variable": "string"
} 

MoveDownInstanceVariable

Move an instance variable from a given class to one of its subclasses.

{
 "type": "MoveDownInstanceVariable",
 "className": "string",
 "variable": "string",
 "target": "string"
} 

AddClassVariable

Add a new class variable to a given class.

{
 "type": "AddClassVariable",
 "className": "string",
 "variable": "string"
} 

RemoveClassVariable

Remove a class variable from a given class.

{
 "type": "RemoveClassVariable",
 "className": "string",
 "variable": "string"
} 

RenameClassVariable

Rename a class variable of a given class.

{
 "type": "RenameClassVariable",
 "className": "string",
 "variable": "string",
 "newName": "string"
} 

RenameCategory

Rename a category within a class.

{
 "type": "RenameCategory",
 "className": "string",
 "category": "string",
 "newName": "string"
} 

RemoveCategory

Remove a category from a class.

{
 "type": "RemoveCategory",
 "className": "string",
 "category": "string"
} 

AddPackage

Add a new package.

{
 "type": "AddPackage",
 "name": "string"
} 

RemovePackage

Remove a given package

{
 "type": "RemovePackage",
 "name": "string"
} 

RenamePackage

Rename a given package.

{
 "type": "RenamePackage",
 "name": "string",
 "newName": "string"
} 

Example:: compile method phi in Float POST /changes

{
	"type": "AddMethod",
	"className": "Float class",
	"category": "constants",
	"sourceCode": "phi\r\t^1.0 + 5.0 sqrt / 2.0",
	"author": "guille"
}

Success Responses

Code : 200 OK

Content: the change applied (see get to see the structure of a change). The change is validated before being applied and updated with some information afterwards, thus, the change returned contains more information. For instance, one of the common properties added to the change is timestamp, corresponding to the moment at which the change is applied. There are some special cases like the selector property in a AddMethod. This property is not required as it is determined by the sourceCode property. However, this property is filled by the server and returned to the client.

Errors

Whenever a change cannot be appplied, the backend should respond with an client error code (typically 409), indicating what went wrong using the description property. Also, the backend might provide one or more suggestions on how to carry on the intended change. These should be variations of the original change, together with a description that could be used by the IDE to propmt the user what they want to do. This is the aspect of an error response data.

{
	"description": "string",
	"suggestions": ["suggestion"]
}

Where, suggestion has the following shape:

{
	"description": "string",
	"changes": ["change"]
}

and changes is the set of changes that will be applied to mitigate the reported error.\

Note that this is a list as it would be necessary to apply several changes to accomplish what the client wanted to do (i.e., the original change). This is better understood by an example like the one below.

Compilation Errors

These errors should be reported with code 409. Like explained above, the payload will contain a description and a list of suggestions. In the case of a compilation error, a more detail description (fullDescription property), and the interval of the error should be provided.

{
	"description": "string",
	"fullDescription": "string",
	"interval": {
		"start": "number",
		"end": "number"
	},
	"suggestions": ["suggestion"]
}

For example, after sending a AddMethod change on Number class with the source code ^1 + , the the following error is returned:

409
{
	"description": "primary missing",
	"fullDescription": "primary missing",
	"interval": {
		"start": 7,
		"end": 7
	}
}

Note that the interval corresponds the the missing part and there are no suggestions.

Here is another example with suggestions: Llt's say we try to compile a method with a single line t := 1 on a class where t is not defined. The error returned should look like:

409
{
	"description": "undeclared t",
	"fullDescription": "undeclared identifier t at line 2 position 2",
	"interval": {
		"start": 4,
		"end": 4
	},
	"suggestions": [
		{
			"description": "Declare 't' as a temporary",
			"changes": [
				{
					"type": "AddMethod",
					"author": "guille",
					"sourceCode": "m\r\t | t | \r\tt := 1",
					"className": "Number",
					"selector": "m",
					"category": "arithmetic"
				}
			]
		}
	]
}

Note that changes contains a list with another AddMethod with a modified source, which corresponds to accepting the suggestion.

Note also that in the case that the original source might contain more than one compilation error. However, these should be presented one at a time, asking the user what suggestion they want, sending the changes of the chosen one, and repeating the process if a new error is reported. For instance, if the code sent in an AddMethod change is the following m t1 := 1. t2 := 2, and neither t1 and t2 are defined, a first response will be like before:

409
{
    "description": "undeclared t1",
    "fullDescription": "undeclared identifier t1 at line 2 position 3",
    "interval": {
        "start": 5,
        "end": 6
    },
    "suggestions": [
        {
            "description": "Declare 't1' as a temporary",
            "changes": [
                {
                    "type": "AddMethod",
                    "author": "guille",
                    "sourceCode": "m\r   | t1 | \r\tt1 := 1.\r  t2 := 2.",
                    "className": "Number",
                    "category": "arithmetic"
                }
            ]
        }
    ]
}

And once the user choses the suggestion, a new error is generated indicating t2 is not defined, but this time based on the code of the previously accepted suggestion.

409
{
    "description": "undeclared t2",
    "fullDescription": "undeclared identifier t2 at line 4 position 3",
    "interval": {
        "start": 26,
        "end": 27
    },
    "suggestions": [
        {
            "description": "Declare 't2' as a temporary",
            "changes": [
                {
                    "type": "AddMethod",
                    "author": "guille",
                    "sourceCode": "m\r   | t1 t2 | \r\tt1 := 1.\r  t2 := 2.",
                    "className": "Number",
                    "category": "arithmetic"
                }
            ]
        }
    ]
}

Confirmation

Notice that this mechanism can be use to just confirm a change on the server side: by just providing a suggestion with the original change (plus a flag with the confirmation) and a description like Are you sure?.

This differs from any confirmation on the IDE side as the backend might have (and surely has) a richer context.

Last updated